Material Ribbon

Material 3 ribbon components for Flutter desktop, web, phone, and adaptive layouts. material_ribbon provides an Office-inspired command surface built from tabs, groups, commands, galleries, and compact form controls.

Features

  • Material 3 ribbon tabs with horizontal scrolling for constrained widths.
  • Contextual tabs that appear only for a matching editor selection.
  • Small, medium, and large commands, including action, toggle, menu, split, and gallery variants.
  • A customizable Quick Access Toolbar, optional persistence, and optional command search.
  • Keyboard key tips (Alt, F10, or a tab/command key tip) and Ctrl+F1 to collapse or expand the ribbon.
  • Ribbon-ready gallery, colour picker, combo box, font picker, text box, and spin box controls.
  • An adaptive compact layout below 720 logical pixels, or whenever compact is set explicitly.

Installation

flutter pub add material_ribbon
import 'package:material_ribbon/material_ribbon.dart';

Quick start

MaterialRibbon is controlled by the host: provide current editor state in RibbonContext and update state from callbacks.

class EditorPage extends StatefulWidget {
  const EditorPage({super.key});

  @override
  State<EditorPage> createState() => _EditorPageState();
}

class _EditorPageState extends State<EditorPage> {
  bool _collapsed = false;
  String? _selectionType;

  @override
  Widget build(BuildContext context) {
    final ribbonContext = RibbonContext(
      selectionType: _selectionType,
      selectionCount: _selectionType == null ? 0 : 1,
    );

    return Scaffold(
      body: Column(
        children: [
          MaterialRibbon(
            context: ribbonContext,
            collapsed: _collapsed,
            onCollapsedChanged: (value) => setState(() => _collapsed = value),
            quickAccessCommands: [
              RibbonCommand(
                id: 'save',
                label: 'Save',
                icon: Icons.save_outlined,
                shortcut: 'Ctrl+S',
                keyTip: 'S',
                onInvoke: () {/* save the document */},
              ),
            ],
            tabs: [
              RibbonTab(
                id: 'home',
                label: 'Home',
                keyTip: 'H',
                groups: [
                  RibbonGroup(
                    label: 'Clipboard',
                    commands: [
                      RibbonCommand(
                        id: 'paste',
                        label: 'Paste',
                        icon: Icons.content_paste_outlined,
                        size: RibbonCommandSize.large,
                        onInvoke: () {/* paste */},
                      ),
                    ],
                  ),
                ],
              ),
              RibbonTab(
                id: 'picture-format',
                label: 'Picture Format',
                isVisible: (value) => value.selectionType == 'image',
                groups: const [],
              ),
            ],
          ),
          const Expanded(child: Placeholder()),
        ],
      ),
    );
  }
}

Commands and groups

Use RibbonCommand for each operation and place commands in a RibbonGroup. Large commands span the group command height; small and medium commands tile vertically. rows controls the number of command rows (from 1 through 3).

RibbonGroup(
  label: 'Paragraph',
  rows: 2,
  commands: [
    RibbonCommand(
      id: 'bold',
      label: 'Bold',
      icon: Icons.format_bold,
      type: RibbonCommandType.toggle,
      checkState: (_) => isBold
          ? RibbonCheckState.checked
          : RibbonCheckState.unchecked,
      onInvoke: toggleBold,
    ),
    RibbonCommand(
      id: 'align',
      label: 'Align',
      icon: Icons.format_align_left,
      type: RibbonCommandType.menu,
      menuCommands: alignmentCommands,
      onInvoke: () {},
    ),
  ],
)

Set isEnabled, isBusy, and disabledReason to derive command state from the current RibbonContext. The ribbon disables unavailable or busy commands and displays the reason in their tooltip.

Contextual tabs

RibbonTab.isVisible is evaluated whenever the supplied RibbonContext changes, making it suitable for selection-sensitive tooling:

RibbonTab(
  id: 'table-layout',
  label: 'Table Layout',
  isVisible: (context) => context.selectionType == 'table',
  groups: tableGroups,
)

Ribbon controls and galleries

RibbonGroup.controls accepts any widget. The package includes compact, controlled widgets intended for this area: RibbonGallery, RibbonColorPicker, RibbonComboBox, RibbonFontPicker, RibbonTextBox, and RibbonSpinBox.

For a gallery, onPreview is called while a pointer enters a cell and onPreviewEnd is called when it leaves the gallery. This lets an editor show a temporary preview and restore the committed value afterwards.

RibbonColorPicker(
  colors: const [Colors.black, Colors.red, Colors.blue],
  value: committedColor,
  onChanged: (color) => setState(() {
    committedColor = color;
    previewColor = color;
  }),
  onPreview: (color) => setState(() => previewColor = color),
  onPreviewEnd: () => setState(() => previewColor = committedColor),
)

Quick Access Toolbar and personalization

Pass quickAccessCommands to set the default Quick Access Toolbar. The older leadingCommands property remains supported as an alias. To allow users to customize the toolbar, provide onPersonalizationChanged, a RibbonPersonalizationStore, or both. The store is application-owned, so it can use shared preferences, a database, or another persistence mechanism.

RibbonPersonalization stores Quick Access command IDs, tab ordering, and hidden tab IDs. Command IDs and tab IDs should therefore be stable and unique.

Optional command palette

RibbonCommandPalette is independent of the ribbon. Place it in MaterialRibbon.commandPalette to show a search field in the desktop ribbon header. It is automatically omitted on narrow layouts.

MaterialRibbon(
  // ...tabs and context...
  commandPalette: RibbonCommandPalette(
    commands: commands,
    context: ribbonContext,
  ),
)

Example

The runnable sample is in example/material_ribbon_example.dart. After creating the example platforms, run it with:

cd example
flutter create --platforms=windows,web .
flutter run -d windows -t material_ribbon_example.dart

API reference

See API.md for the complete public API, constructor parameters, and behaviour notes.

Development

flutter analyze
flutter test

Libraries

main
material_ribbon
Material 3 components for building a productive, adaptive ribbon UI.