Navigation

Sidebar

A sidebar widget that provides an opinionated layout for navigation on the side of the screen.

A sidebar is typically used with FScaffold. Usage of FScaffold can be found here.

1@override
2Widget build(BuildContext context) => FScaffold(
3 sidebar: FSidebar(
4 header: Padding(
5 padding: const .symmetric(horizontal: 16),
6 child: Column(
7 crossAxisAlignment: .start,
8 children: [
9 Padding(
10 padding: const .fromLTRB(16, 8, 16, 16),
11 child: SvgPicture.network(
12 context.theme.colors.brightness == .light
13 ? 'https://forui.dev/light_logo.svg'
14 : 'https://forui.dev/dark_logo.svg',
15 height: 24,
16 colorFilter: ColorFilter.mode(
17 context.theme.colors.foreground,
18 .srcIn,
19 ),
20 ),
21 ),
22 const FDivider(style: .delta(padding: .value(.zero))),
23 ],
24 ),
25 ),
26 footer: Padding(
27 padding: const .symmetric(horizontal: 16),
28 child: FCard.raw(
29 child: Padding(
30 padding: const .symmetric(vertical: 12, horizontal: 16),
31 child: Row(
32 spacing: 10,
33 children: [
34 FAvatar.raw(
35 child: Icon(
36 FIcons.userRound,
37 size: 18,
38 color: context.theme.colors.mutedForeground,
39 ),
40 ),
41 Expanded(
42 child: Column(
43 crossAxisAlignment: .start,
44 spacing: 2,
45 children: [
46 Text(
47 'Dash',
48 style: context.theme.typography.sm.copyWith(
49 fontWeight: .bold,
50 color: context.theme.colors.foreground,
51 ),
52 overflow: .ellipsis,
53 ),
54 Text(
55 'dash@forui.dev',
56 style: context.theme.typography.xs.copyWith(
57 color: context.theme.colors.mutedForeground,
58 ),
59 overflow: .ellipsis,
60 ),
61 ],
62 ),
63 ),
64 ],
65 ),
66 ),
67 ),
68 ),
69 children: [
70 FSidebarGroup(
71 label: const Text('Overview'),
72 children: [
73 FSidebarItem(
74 icon: const Icon(FIcons.school),
75 label: const Text('Getting Started'),
76 initiallyExpanded: true,
77 onPress: () {},
78 children: [
79 FSidebarItem(
80 label: const Text('Installation'),
81 selected: true,
82 onPress: () {},
83 ),
84 FSidebarItem(label: const Text('Themes'), onPress: () {}),
85 FSidebarItem(label: const Text('Typography'), onPress: () {}),
86 ],
87 ),
88 FSidebarItem(
89 icon: const Icon(FIcons.code),
90 label: const Text('API Reference'),
91 onPress: () {},
92 ),
93 FSidebarItem(
94 icon: const Icon(FIcons.box),
95 label: const Text('Pub Dev'),
96 onPress: () {},
97 ),
98 ],
99 ),
100 FSidebarGroup(
101 action: const Icon(FIcons.plus),
102 onActionPress: () {},
103 label: const Text('Widgets'),
104 children: [
105 FSidebarItem(
106 icon: const Icon(FIcons.circleSlash),
107 label: const Text('Divider'),
108 onPress: () {},
109 ),
110 FSidebarItem(
111 icon: const Icon(FIcons.scaling),
112 label: const Text('Resizable'),
113 onPress: () {},
114 ),
115 FSidebarItem(
116 icon: const Icon(FIcons.layoutDashboard),
117 label: const Text('Scaffold'),
118 onPress: () {},
119 ),
120 ],
121 ),
122 ],
123 ),
124 child: Padding(
125 padding: const .symmetric(vertical: 14),
126 child: Column(
127 crossAxisAlignment: .start,
128 spacing: 12,
129 children: [
130 FBreadcrumb(
131 children: [
132 FBreadcrumbItem(onPress: () {}, child: const Text('Forui')),
133 FBreadcrumbItem.collapsed(
134 menu: [
135 FItemGroup(
136 children: [
137 FItem(title: const Text('Documentation'), onPress: () {}),
138 FItem(title: const Text('Themes'), onPress: () {}),
139 ],
140 ),
141 ],
142 ),
143 FBreadcrumbItem(onPress: () {}, child: const Text('Overview')),
144 const FBreadcrumbItem(current: true, child: Text('Installation')),
145 ],
146 ),
147 Expanded(
148 child: Container(
149 decoration: BoxDecoration(
150 color: context.theme.colors.muted,
151 borderRadius: context.theme.style.borderRadius.md,
152 ),
153 ),
154 ),
155 Expanded(
156 flex: 3,
157 child: Container(
158 decoration: BoxDecoration(
159 color: context.theme.colors.muted,
160 borderRadius: context.theme.style.borderRadius.md,
161 ),
162 ),
163 ),
164 ],
165 ),
166 ),
167);
168

CLI

To generate a specific style for customization:

dart run forui style create sidebar
dart run forui style create sidebar-group
dart run forui style create sidebar-item

Anatomy

This segment describes the anatomy of the various elements of a sidebar.

FSidebar

The widget that provides an opinionated layout on the side of the screen. The widget has the following sections:

NameParameterPositionOptional
headerheaderstickyYes
contentchild/childrenscrollableNo
footerfooterstickyYes

FSidebarGroup

A widget that is used to group several FSidebarItems.

FSidebarItem

Represents an item on the sidebar. May be nested in FSidebarItem.children to create nested items.

Usage

FSidebar(...)

1FSidebar(
2 style: const .delta(headerPadding: .value(.fromLTRB(0, 16, 0, 0))),
3 header: const Text('Header'),
4 children: [
5 FSidebarGroup(
6 label: const Text('Navigation'),
7 children: [
8 FSidebarItem(
9 icon: const Icon(FIcons.house),
10 label: const Text('Home'),
11 onPress: () {},
12 ),
13 FSidebarItem(
14 icon: const Icon(FIcons.settings),
15 label: const Text('Settings'),
16 onPress: () {},
17 ),
18 ],
19 ),
20 ],
21 footer: const Text('Footer'),
22)

FSidebar.builder(...)

1FSidebar.builder(
2 style: const .delta(headerPadding: .value(.fromLTRB(0, 16, 0, 0))),
3 header: const Text('Header'),
4 itemBuilder: (context, index) =>
5 FSidebarItem(label: Text('Item $index'), onPress: () {}),
6 itemCount: 10,
7 footer: const Text('Footer'),
8)

FSidebar.raw(...)

1FSidebar.raw(
2 style: const .delta(headerPadding: .value(.fromLTRB(0, 16, 0, 0))),
3 header: const Text('Header'),
4 child: ListView(
5 children: [FSidebarItem(label: const Text('Custom Item'), onPress: () {})],
6 ),
7 footer: const Text('Footer'),
8)

FSidebarGroup(...)

1FSidebarGroup(
2 style: const .delta(padding: .value(.symmetric(horizontal: 8))),
3 label: const Text('Navigation'),
4 action: const Icon(FIcons.plus),
5 children: [
6 FSidebarItem(label: const Text('Home'), onPress: () {}),
7 FSidebarItem(label: const Text('Settings'), onPress: () {}),
8 ],
9)

FSidebarItem(...)

1FSidebarItem(
2 style: const .delta(padding: .value(.symmetric(horizontal: 8))),
3 selected: false,
4 initiallyExpanded: false,
5 icon: const Icon(FIcons.house),
6 label: const Text('Home'),
7 children: [
8 FSidebarItem(label: const Text('Nested Item 1'), onPress: () {}),
9 FSidebarItem(label: const Text('Nested Item 2'), onPress: () {}),
10 ],
11)

Examples

Sheet Sidebar

Suited for devices with limited screen space.

1@override
2Widget build(BuildContext context) => Center(
3 child: FButton(
4 variant: .outline,
5 size: .sm,
6 mainAxisSize: .min,
7 child: const Text('Open Sidebar'),
8 onPress: () => showFSheet(
9 context: context,
10 side: .ltr,
11 builder: (context) => DecoratedBox(
12 decoration: BoxDecoration(color: context.theme.colors.background),
13 child: FSidebar(
14 style: const .delta(
15 constraints: BoxConstraints(minWidth: 300, maxWidth: 300),
16 ),
17 header: Padding(
18 padding: const .symmetric(horizontal: 16),
19 child: Column(
20 crossAxisAlignment: .start,
21 children: [
22 Padding(
23 padding: const .fromLTRB(16, 8, 16, 16),
24 child: SvgPicture.network(
25 context.theme.colors.brightness == .light
26 ? 'https://forui.dev/light_logo.svg'
27 : 'https://forui.dev/dark_logo.svg',
28 height: 24,
29 colorFilter: ColorFilter.mode(
30 context.theme.colors.foreground,
31 .srcIn,
32 ),
33 ),
34 ),
35 const FDivider(style: .delta(padding: .value(.zero))),
36 ],
37 ),
38 ),
39 footer: Padding(
40 padding: const .symmetric(horizontal: 16),
41 child: FCard.raw(
42 child: Padding(
43 padding: const .symmetric(vertical: 12, horizontal: 16),
44 child: Row(
45 spacing: 10,
46 children: [
47 FAvatar.raw(
48 child: Icon(
49 FIcons.userRound,
50 size: 18,
51 color: context.theme.colors.mutedForeground,
52 ),
53 ),
54 Expanded(
55 child: Column(
56 crossAxisAlignment: .start,
57 spacing: 2,
58 children: [
59 Text(
60 'Dash',
61 style: context.theme.typography.sm.copyWith(
62 fontWeight: .bold,
63 color: context.theme.colors.foreground,
64 ),
65 overflow: .ellipsis,
66 ),
67 Text(
68 'dash@forui.dev',
69 style: context.theme.typography.xs.copyWith(
70 color: context.theme.colors.mutedForeground,
71 ),
72 overflow: .ellipsis,
73 ),
74 ],
75 ),
76 ),
77 ],
78 ),
79 ),
80 ),
81 ),
82 children: [
83 FSidebarGroup(
84 label: const Text('Overview'),
85 children: [
86 FSidebarItem(
87 icon: const Icon(FIcons.school),
88 label: const Text('Getting Started'),
89 initiallyExpanded: true,
90 onPress: () {},
91 children: [
92 FSidebarItem(
93 label: const Text('Installation'),
94 selected: true,
95 onPress: () {},
96 ),
97 FSidebarItem(label: const Text('Themes'), onPress: () {}),
98 FSidebarItem(
99 label: const Text('Typography'),
100 onPress: () {},
101 ),
102 ],
103 ),
104 FSidebarItem(
105 icon: const Icon(FIcons.code),
106 label: const Text('API Reference'),
107 onPress: () {},
108 ),
109 FSidebarItem(
110 icon: const Icon(FIcons.box),
111 label: const Text('Pub Dev'),
112 onPress: () {},
113 ),
114 ],
115 ),
116 FSidebarGroup(
117 action: const Icon(FIcons.plus),
118 onActionPress: () {},
119 label: const Text('Widgets'),
120 children: [
121 FSidebarItem(
122 icon: const Icon(FIcons.circleSlash),
123 label: const Text('Divider'),
124 onPress: () {},
125 ),
126 FSidebarItem(
127 icon: const Icon(FIcons.scaling),
128 label: const Text('Resizable'),
129 onPress: () {},
130 ),
131 FSidebarItem(
132 icon: const Icon(FIcons.layoutDashboard),
133 label: const Text('Scaffold'),
134 onPress: () {},
135 ),
136 ],
137 ),
138 ],
139 ),
140 ),
141 ),
142 ),
143);
144

Custom Width

1@override
2Widget build(BuildContext _) => FSidebar(
3 style: const .delta(
4 constraints: BoxConstraints(minWidth: 500, maxWidth: 500),
5 ),
6 children: [
7 FSidebarGroup(
8 children: [
9 FSidebarItem(
10 icon: const Icon(FIcons.layoutDashboard),
11 label: const Text('Dashboard'),
12 selected: true,
13 onPress: () {},
14 ),
15 FSidebarItem(
16 icon: const Icon(FIcons.chartLine),
17 label: const Text('Analytics'),
18 onPress: () {},
19 ),
20 FSidebarItem(
21 icon: const Icon(FIcons.chartBar),
22 label: const Text('Reports'),
23 initiallyExpanded: true,
24 children: [
25 FSidebarItem(label: const Text('Daily'), onPress: () {}),
26 FSidebarItem(label: const Text('Weekly'), onPress: () {}),
27 FSidebarItem(label: const Text('Monthly'), onPress: () {}),
28 ],
29 ),
30 ],
31 ),
32 ],
33);
34

Nested FSidebarItem

1@override
2Widget build(BuildContext _) => FSidebar(
3 style: const .delta(
4 constraints: BoxConstraints(minWidth: 300, maxWidth: 300),
5 ),
6 children: [
7 FSidebarGroup(
8 children: [
9 FSidebarItem(
10 icon: const Icon(FIcons.userRound),
11 label: const Text('Account'),
12 initiallyExpanded: true,
13 children: [
14 FSidebarItem(
15 label: const Text('Profile'),
16 children: [
17 FSidebarItem(
18 label: const Text('Personal Info'),
19 onPress: () {},
20 ),
21 FSidebarItem(label: const Text('Preferences'), onPress: () {}),
22 ],
23 ),
24 FSidebarItem(
25 label: const Text('Security'),
26 initiallyExpanded: true,
27 children: [
28 FSidebarItem(
29 label: const Text('Password'),
30 initiallyExpanded: true,
31 children: [
32 FSidebarItem(
33 label: const Text('Change Password'),
34 onPress: () {},
35 ),
36 FSidebarItem(
37 label: const Text('Password History'),
38 onPress: () {},
39 ),
40 ],
41 ),
42 FSidebarItem(
43 label: const Text('Two-Factor Authentication'),
44 onPress: () {},
45 ),
46 FSidebarItem(
47 label: const Text('Device History'),
48 onPress: () {},
49 ),
50 ],
51 ),
52 FSidebarItem(label: const Text('Notifications'), onPress: () {}),
53 ],
54 ),
55 FSidebarItem(
56 icon: const Icon(FIcons.palette),
57 label: const Text('Appearance'),
58 onPress: () {},
59 ),
60 FSidebarItem(
61 icon: const Icon(FIcons.settings),
62 label: const Text('System'),
63 onPress: () {},
64 ),
65 ],
66 ),
67 ],
68);
69

On this page