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) andCtrl+F1to 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
compactis 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.