material_ribbon 1.1.0
material_ribbon: ^1.1.0 copied to clipboard
Material 3 ribbon components for Flutter desktops, webs, phones, and adaptive layouts.
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