quiet_dock

A floating glass bottom dock for Flutter — the mobile navigation shell, the swipeable page sliding and the tab-switching logic in one widget.

quiet_dock

quiet_dock demo

/// Note: The GIF may look laggy, but the actual animation is smooth. /// The GIF has reduced frames to keep the file size smaller.

  • Floating frosted dock with an animated sliding pill indicator
  • Swipe left/right to slide between screens, perfectly in sync with the dock
  • One function handles every tab change: tap, swipe, quick-grid tile or code
  • Optional center action that pops an animated quick grid of extra destinations
  • Automatic side navigation rail on tablet/desktop widths
  • Zero dependencies beyond Flutter; works with any router (go_router, Navigator, none)

Install

dependencies:
  quiet_dock: ^0.1.0

Quick start

import 'package:quiet_dock/quiet_dock.dart';

QuietDockScaffold(
  destinations: const [
    QuietDockDestination(
      icon: Icons.home_outlined,
      selectedIcon: Icons.home_rounded,
      label: 'Home',
    ),
    QuietDockDestination(icon: Icons.checklist_outlined, label: 'Todos'),
    QuietDockDestination(icon: Icons.notes_outlined, label: 'Notes'),
    QuietDockDestination(icon: Icons.settings_outlined, label: 'Settings'),
  ],
  pageBuilder: (context, index) => pages[index],
  onDestinationSelected: (index) => debugPrint('tab $index'),
);

That is the whole integration: dock, page sliding, keep-alive pages and the wide-screen rail.

Quick grid center action

Drop extra destinations behind a center trigger that springs open above the dock:

QuietDockScaffold(
  destinations: destinations,
  pageBuilder: (context, i) => pages[i],
  centerAction: QuietDockCenterAction(
    columns: 3,
    items: [
      QuickGridItem(icon: Icons.flag_rounded, label: 'Goals', onTap: openGoals),
      QuickGridItem(icon: Icons.school_rounded, label: 'Courses', onTap: openCourses),
      // ...any number of tiles
    ],
  ),
);

One function for tab switching

Dock taps, swipes, quick-grid tiles and QuietDockController.goToIndex all funnel through the same internal selector, which updates the index, slides (or jumps, when the distance is greater than one) the page, and calls onDestinationSelected exactly once. Put your routing there:

final controller = QuietDockController();

QuietDockScaffold(
  controller: controller,
  destinations: destinations,
  pageBuilder: (context, i) => pages[i],
  onDestinationSelected: (index) => context.go(routes[index]),
);

controller.goToIndex(2); // same path as a tap

go_router

quiet_dock does not depend on a router. With go_router, wrap the scaffold in a ShellRoute and drive it from the callback:

ShellRoute(
  builder: (context, state, child) {
    final location = state.uri.path;
    final index = routes.indexWhere(location.startsWith);
    return QuietDockScaffold(
      initialIndex: index < 0 ? 0 : index,
      destinations: destinations,
      pageBuilder: (context, i) => pages[i],
      onDestinationSelected: (i) => context.go(routes[i]),
    );
  },
  routes: [...],
);

Theming

Colors default to the ambient ThemeData (light and dark) and every value is overridable:

QuietDockScaffold(
  theme: const QuietDockTheme(
    width: 320,
    height: 60,
    radius: 30,
    frosted: true,
    blur: 22,
    showLabels: true,
    hapticFeedback: true,
  ),
  // ...
);

Other pieces

Widget Use it for
QuietDockScaffold Complete shell: dock + sliding pages + rail
QuietDock Just the dock bar, over your own body
QuietDockRail Just the wide-screen rail
QuietQuickGrid The popover grid on its own

Example

cd example
flutter run

License

MIT

Libraries

quiet_dock
A floating glass bottom dock for Flutter apps, with swipeable page sliding, a quick-grid center action and a wide-screen navigation rail.