Overlay

Popover Menu

A popover menu displays a menu in a portal aligned to a child.

1@override
2Widget build(BuildContext _) => FHeader(
3 title: const Text('Edit Notes'),
4 suffixes: [
5 FPopoverMenu(
6 autofocus: true,
7 menuAnchor: .topRight,
8 childAnchor: .bottomRight,
9 menu: [
10 .group(
11 children: [
12 .item(
13 prefix: const Icon(FLucideIcons.user),
14 title: const Text('Personalization'),
15 onPress: () {},
16 ),
17 .item(
18 prefix: const Icon(FLucideIcons.paperclip),
19 title: const Text('Add attachments'),
20 onPress: () {},
21 ),
22 .item(
23 prefix: const Icon(FLucideIcons.qrCode),
24 title: const Text('Scan Document'),
25 onPress: () {},
26 ),
27 ],
28 ),
29 .group(
30 children: [
31 .item(
32 prefix: const Icon(FLucideIcons.list),
33 title: const Text('List View'),
34 onPress: () {},
35 ),
36 .item(
37 prefix: const Icon(FLucideIcons.layoutGrid),
38 title: const Text('Grid View'),
39 onPress: () {},
40 ),
41 ],
42 ),
43 ],
44 builder: (_, controller, _) => FHeaderAction(
45 icon: const Icon(FLucideIcons.ellipsis),
46 onPress: controller.toggle,
47 ),
48 ),
49 ],
50);
51

CLI

To generate a specific style for customization:

dart run forui style create popover-menu

Usage

FPopoverMenu(...)

1FPopoverMenu(
2 style: const .delta(maxWidth: 250),
3 faded: null,
4 divider: .full,
5 menu: [
6 .group(
7 children: [
8 .item(title: const Text('Edit'), onPress: () {}),
9 .item(title: const Text('Delete'), onPress: () {}),
10 ],
11 ),
12 ],
13 menuBuilder: (context, controller, menu) => menu!,
14 builder: (context, controller, child) => child!,
15 child: FButton(onPress: () {}, child: const Text('Menu')),
16)

FPopoverMenu.tiles(...)

1FPopoverMenu.tiles(
2 style: const .delta(maxWidth: 250),
3 faded: null,
4 divider: .full,
5 menu: [
6 .group(
7 children: [
8 .tile(title: const Text('Edit'), onPress: () {}),
9 .tile(title: const Text('Delete'), onPress: () {}),
10 ],
11 ),
12 ],
13 menuBuilder: (context, controller, menu) => menu!,
14 builder: (context, controller, child) => child!,
15 child: FButton(onPress: () {}, child: const Text('Menu')),
16)

Examples

Nested Submenu

1@override
2Widget build(BuildContext _) => FHeader(
3 title: const Text('Edit Notes'),
4 suffixes: [
5 FPopoverMenu(
6 autofocus: true,
7 menuAnchor: .topRight,
8 childAnchor: .bottomRight,
9 menu: [
10 .group(
11 children: [
12 .item(
13 prefix: const Icon(FLucideIcons.user),
14 title: const Text('Personalization'),
15 onPress: () {},
16 ),
17 .item(
18 prefix: const Icon(FLucideIcons.paperclip),
19 title: const Text('Add attachments'),
20 onPress: () {},
21 ),
22 .submenu(
23 title: const Text('Share'),
24 prefix: const Icon(FLucideIcons.share2),
25 submenu: [
26 .group(
27 children: [
28 .item(
29 prefix: const Icon(FLucideIcons.mail),
30 title: const Text('Email'),
31 onPress: () {},
32 ),
33 .item(
34 prefix: const Icon(FLucideIcons.messageSquare),
35 title: const Text('Message'),
36 onPress: () {},
37 ),
38 .item(
39 prefix: const Icon(FLucideIcons.link),
40 title: const Text('Copy Link'),
41 onPress: () {},
42 ),
43 ],
44 ),
45 ],
46 ),
47 ],
48 ),
49 .group(
50 children: [
51 .item(
52 prefix: const Icon(FLucideIcons.list),
53 title: const Text('List View'),
54 onPress: () {},
55 ),
56 .item(
57 prefix: const Icon(FLucideIcons.layoutGrid),
58 title: const Text('Grid View'),
59 onPress: () {},
60 ),
61 ],
62 ),
63 ],
64 builder: (_, controller, _) => FHeaderAction(
65 icon: const Icon(FLucideIcons.ellipsis),
66 onPress: controller.toggle,
67 ),
68 ),
69 ],
70);
71

Tiles

1@override
2Widget build(BuildContext _) => FHeader(
3 title: const Text('Edit Notes'),
4 suffixes: [
5 FPopoverMenu.tiles(
6 autofocus: true,
7 menuAnchor: .topRight,
8 childAnchor: .bottomRight,
9 menu: [
10 .group(
11 children: [
12 .tile(
13 prefix: const Icon(FLucideIcons.user),
14 title: const Text('Personalization'),
15 onPress: () {},
16 ),
17 .tile(
18 prefix: const Icon(FLucideIcons.paperclip),
19 title: const Text('Add attachments'),
20 onPress: () {},
21 ),
22 .tile(
23 prefix: const Icon(FLucideIcons.qrCode),
24 title: const Text('Scan Document'),
25 onPress: () {},
26 ),
27 ],
28 ),
29 .group(
30 children: [
31 .tile(
32 prefix: const Icon(FLucideIcons.list),
33 title: const Text('List View'),
34 onPress: () {},
35 ),
36 .tile(
37 prefix: const Icon(FLucideIcons.layoutGrid),
38 title: const Text('Grid View'),
39 onPress: () {},
40 ),
41 ],
42 ),
43 ],
44 builder: (_, controller, _) => FHeaderAction(
45 icon: const Icon(FLucideIcons.ellipsis),
46 onPress: controller.toggle,
47 ),
48 ),
49 ],
50);
51

Blurred Barrier

1@override
2Widget build(BuildContext context) => Column(
3 mainAxisAlignment: .center,
4 crossAxisAlignment: .end,
5 children: [
6 Column(
7 crossAxisAlignment: .start,
8 children: [
9 Text(
10 'Layer Properties',
11 style: context.theme.typography.display.xl.copyWith(
12 fontWeight: .bold,
13 ),
14 ),
15 const SizedBox(height: 20),
16 const FTextField(
17 control: .managed(
18 initial: TextEditingValue(text: 'Header Component'),
19 ),
20 ),
21 const SizedBox(height: 16),
22 const FTextField(
23 control: .managed(initial: TextEditingValue(text: 'Navigation Bar')),
24 ),
25 const SizedBox(height: 30),
26 ],
27 ),
28 FPopoverMenu(
29 style: .delta(
30 barrierFilter: () =>
31 (animation) => ImageFilter.compose(
32 outer: ImageFilter.blur(
33 sigmaX: animation * 5,
34 sigmaY: animation * 5,
35 ),
36 inner: ColorFilter.mode(
37 Color.lerp(
38 const Color(0x00000000),
39 const Color(0x33000000),
40 animation,
41 )!,
42 BlendMode.srcOver,
43 ),
44 ),
45 ),
46 cutoutBuilder: FModalBarrier
47 .defaultCutoutBuilder, // Replace this to create a custom cutout shape.
48 autofocus: true,
49 menuAnchor: .topRight,
50 childAnchor: .bottomRight,
51 menu: [
52 .group(
53 children: [
54 .item(
55 prefix: const Icon(FLucideIcons.user),
56 title: const Text('Personalization'),
57 onPress: () {},
58 ),
59 .item(
60 prefix: const Icon(FLucideIcons.paperclip),
61 title: const Text('Add attachments'),
62 onPress: () {},
63 ),
64 .item(
65 prefix: const Icon(FLucideIcons.qrCode),
66 title: const Text('Scan Document'),
67 onPress: () {},
68 ),
69 ],
70 ),
71 .group(
72 children: [
73 .item(
74 prefix: const Icon(FLucideIcons.list),
75 title: const Text('List View'),
76 onPress: () {},
77 ),
78 .item(
79 prefix: const Icon(FLucideIcons.layoutGrid),
80 title: const Text('Grid View'),
81 onPress: () {},
82 ),
83 ],
84 ),
85 ],
86 builder: (_, controller, _) => FButton(
87 variant: .outline,
88 size: .sm,
89 mainAxisSize: .min,
90 onPress: controller.toggle,
91 child: const Text('Open menu'),
92 ),
93 ),
94 ],
95);
96

On this page