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(FIcons.user),
14 title: const Text('Personalization'),
15 onPress: () {},
16 ),
17 .item(
18 prefix: const Icon(FIcons.paperclip),
19 title: const Text('Add attachments'),
20 onPress: () {},
21 ),
22 .item(
23 prefix: const Icon(FIcons.qrCode),
24 title: const Text('Scan Document'),
25 onPress: () {},
26 ),
27 ],
28 ),
29 .group(
30 children: [
31 .item(
32 prefix: const Icon(FIcons.list),
33 title: const Text('List View'),
34 onPress: () {},
35 ),
36 .item(
37 prefix: const Icon(FIcons.layoutGrid),
38 title: const Text('Grid View'),
39 onPress: () {},
40 ),
41 ],
42 ),
43 ],
44 builder: (_, controller, _) => FHeaderAction(
45 icon: const Icon(FIcons.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 divider: .full,
4 menu: [
5 .group(
6 children: [
7 .item(title: const Text('Edit'), onPress: () {}),
8 .item(title: const Text('Delete'), onPress: () {}),
9 ],
10 ),
11 ],
12 menuBuilder: (context, controller, menu) => menu!,
13 builder: (context, controller, child) => child!,
14 child: FButton(onPress: () {}, child: const Text('Menu')),
15)

FPopoverMenu.tiles(...)

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

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

On this page