// While a Tooltip component exists, for menus it's best to apply
// tooltip classes directly to the MenuItem to preserve the required
// ul > li > a HTML structure for correct styling.
Menu(
style: [BgUtil.base200, Effects.roundedBox],
[
MenuItem(
[Icon('home')],
classes: 'tooltip tooltip-right',
attributes: {'data-tip': 'Home'},
),
MenuItem(
[Icon('info')],
classes: 'tooltip tooltip-right',
attributes: {'data-tip': 'Details'},
),
MenuItem(
[Icon('analytics')],
classes: 'tooltip tooltip-right',
attributes: {'data-tip': 'Stats'},
),
],
)
Menu(
style: [Menu.horizontal, BgUtil.base200, Effects.roundedBox],
[
MenuItem(
[Icon('home')],
classes: 'tooltip',
attributes: {'data-tip': 'Home'},
),
MenuItem(
[Icon('info')],
classes: 'tooltip',
attributes: {'data-tip': 'Details'},
),
MenuItem(
[Icon('analytics')],
classes: 'tooltip',
attributes: {'data-tip': 'Stats'},
),
],
)
Menu(style: [Menu.xs, ...], [/* ... */]),
Menu(style: [Menu.sm, ...], [/* ... */]),
Menu(style: [Menu.md, ...], [/* ... */]), // Default
Menu(style: [Menu.lg, ...], [/* ... */]),
Menu(style: [Menu.xl, ...], [/* ... */]),
Menu(
style: [BgUtil.base200, Size.w56, Effects.roundedBox],
[
MenuItem([text('Enabled item')]),
MenuItem([text('Disabled item')], isDisabled: true),
MenuItem([text('Disabled item')], isDisabled: true),
],
)
Menu(
style: [Menu.horizontal.at(Breakpoint.lg), BgUtil.base200, Effects.roundedBox],
[
MenuItem([Icon('home'), text('Inbox'), Badge([text('99+')], style: [Badge.sm])]),
MenuItem([Icon('info'), text('Updates'), Badge([text('NEW')], style: [Badge.xs, Badge.warning])]),
MenuItem([text('Stats'), Badge([], style: [Badge.xs, Badge.info])]),
],
)
This is a hoverable submenu, suitable for horizontal menus.
Menu(
style: [BgUtil.base200, Size.w56, Effects.roundedBox],
[
MenuItem([text('Item 1')]),
MenuHoverSubmenu(
label: text('Parent'),
children: [
MenuItem([text('Submenu 1')]),
MenuItem([text('Submenu 2')]),
MenuHoverSubmenu(
label: text('Parent'),
children: [
MenuItem([text('Submenu 1')]),
MenuItem([text('Submenu 2')]),
],
),
],
),
MenuItem([text('Item 3')]),
],
)
Uses the MenuSubmenu component which renders accessible <details> and <summary> tags.
Menu(
style: [BgUtil.base200, Size.w56, Effects.roundedBox],
[
MenuItem([text('Item 1')]),
MenuSubmenu(
initiallyOpen: true,
label: text('Parent'),
children: [
MenuItem([text('Submenu 1')]),
MenuItem([text('Submenu 2')]),
MenuSubmenu(
initiallyOpen: true,
label: text('Parent'),
children: [
MenuItem([text('Submenu 1')]),
MenuItem([text('Submenu 2')]),
],
),
],
),
MenuItem([text('Item 3')]),
],
)
You can open/close the submenu by managing a state variable.
class JsControlledSubmenu extends StatefulComponent {
bool _isOpen = false;
@override
State<StatefulComponent> createState() => _JsControlledSubmenuState();
}
class _JsControlledSubmenuState extends State<JsControlledSubmenu> {
@override
Component build(BuildContext context) {
return Menu(
style: [BgUtil.base200, Size.w56, Effects.roundedBox],
[
MenuItem([text('Item 1')]),
li([
MenuDropdownToggle(
[text('Parent')],
onClick: (_) => setState(() => _isOpen = !_isOpen),
),
MenuDropdownContent(
[
MenuItem([text('Submenu 1')]),
MenuItem([text('Submenu 2')]),
],
// Conditionally add the 'menu-dropdown-show' class
classes: _isOpen ? 'menu-dropdown-show' : '',
),
]),
],
);
}
}
- resume.pdf
-
My Files
- reports-final-2.pdf
// For pixel-perfect replication, raw SVG helpers are used for this example.
Component _fileTreeFileIcon() => svg(/* ... */);
Component _fileTreeFolderIcon() => svg(/* ... */);
Component _fileTreeImageIcon() => svg(/* ... */);
Menu(
style: [Menu.xs, BgUtil.base200, Effects.roundedBox, Size.wFull, Size.maxWxs],
[
MenuItem([_fileTreeFileIcon(), text('resume.pdf')]),
MenuSubmenu(
label: Component.element(tag: 'span', children: [_fileTreeFolderIcon(), text('My Files')]),
initiallyOpen: true,
children: [
MenuItem([_fileTreeFileIcon(), text('Project-final.psd')]),
// ... more items and nested submenus
],
),
MenuItem([_fileTreeFileIcon(), text('reports-final-2.pdf')]),
],
)
Menu(
style: [
Menu.horizontal.at(Breakpoint.xl),
BgUtil.base200,
Effects.roundedBox,
Size.minWMax.at(Breakpoint.lg),
],
[
MenuHoverSubmenu(label: text('Solutions'), children: [ /* ... */ ]),
MenuHoverSubmenu(label: text('Enterprise'), children: [ /* ... */ ]),
MenuHoverSubmenu(label: text('Products'), children: [
MenuItem([text('UI Kit')]),
// ... more items
MenuHoverSubmenu(label: text('Open source'), children: [ /* ... nested items */ ])
]),
MenuHoverSubmenu(label: text('Company'), children: [ /* ... */ ]),
],
)
Menu(
style: [Menu.horizontal.at(Breakpoint.lg), BgUtil.base200, Effects.roundedBox],
classes: 'lg:mb-64', // Margin for visibility in preview
[
MenuItem([text('Item 1')]),
MenuSubmenu(
label: text('Parent item'),
initiallyOpen: true,
children: [
MenuItem([text('Submenu 1')]),
MenuItem([text('Submenu 2')]),
MenuSubmenu(
label: text('Parent'),
initiallyOpen: true,
children: [
MenuItem([text('item 1')]),
MenuItem([text('item 2')]),
]
)
]
),
MenuItem([text('Item 3')]),
]
)