Tile

Select Tile Group

A group of tiles that allow users to make a selection from a set of options.

For desktop, a select group is generally recommended over this.

1enum Sidebar { recents, home, applications }
2
3class SelectTileGroupExample extends StatelessWidget {
4 @override
5 Widget build(BuildContext _) => FSelectTileGroup<Sidebar>(
6 control: const .managed(initial: {.recents}),
7 label: const Text('Sidebar'),
8 description: const Text('These will be shown in the sidebar.'),
9 children: const [
10 .tile(
11 title: Text('Recents'),
12 suffix: Icon(FIcons.timer),
13 value: .recents,
14 ),
15 .tile(title: Text('Home'), suffix: Icon(FIcons.house), value: .home),
16 .tile(
17 title: Text('Applications'),
18 suffix: Icon(FIcons.appWindowMac),
19 value: .applications,
20 ),
21 ],
22 );
23}
24

CLI

To generate and customize this style:

dart run forui style create select-tile-group

Usage

FSelectTileGroup(...)

1FSelectTileGroup<String>(
2 style: const .delta(dividerWidth: 1),
3 enabled: true,
4 divider: .indented,
5 children: const [
6 .tile(title: Text('Apple'), value: 'apple'),
7 .tile(title: Text('Banana'), value: 'banana'),
8 .tile(title: Text('Cherry'), value: 'cherry'),
9 ],
10)

FSelectTileGroup.builder(...)

1FSelectTileGroup<String>.builder(
2 style: const .delta(dividerWidth: 1),
3 enabled: true,
4 divider: .indented,
5 tileBuilder: (context, index) =>
6 FSelectTile(title: Text('Item $index'), value: 'item_$index'),
7 count: 10,
8)

FSelectTile(...)

1FSelectTile<String>(
2 style: const .delta(margin: .zero),
3 enabled: true,
4 value: 'apple',
5 title: const Text('Apple'),
6 subtitle: const Text('A red fruit'),
7 details: const Text(r'$1.99'),
8 checkedIcon: const Icon(FIcons.check),
9 uncheckedIcon: null,
10 suffix: null,
11)

FSelectTile.suffix(...)

1FSelectTile<String>.suffix(
2 style: const .delta(margin: .zero),
3 enabled: true,
4 value: 'apple',
5 title: const Text('Apple'),
6 subtitle: const Text('A red fruit'),
7 details: const Text(r'$1.99'),
8 checkedIcon: const Icon(FIcons.check),
9 uncheckedIcon: null,
10 prefix: null,
11)

Examples

Behavior

Scrollable

1enum Sidebar { recents, home, applications }
2
3class ScrollableSelectTileGroupExample extends StatelessWidget {
4 @override
5 Widget build(BuildContext _) => FSelectTileGroup<Sidebar>(
6 control: const .managed(initial: {.recents}),
7 label: const Text('Sidebar'),
8 description: const Text('These will be shown in the sidebar.'),
9 maxHeight: 100,
10 children: const [
11 .tile(
12 title: Text('Recents'),
13 suffix: Icon(FIcons.timer),
14 value: .recents,
15 ),
16 .tile(title: Text('Home'), suffix: Icon(FIcons.house), value: .home),
17 .tile(
18 title: Text('Applications'),
19 suffix: Icon(FIcons.appWindowMac),
20 value: .applications,
21 ),
22 ],
23 );
24}
25

Lazy Scrollable

1@override
2Widget build(BuildContext _) => FSelectTileGroup.builder(
3 control: const .managed(initial: {1}),
4 label: const Text('Applicable values'),
5 maxHeight: 200,
6 tileBuilder: (context, index) =>
7 .tile(title: Text('Tile $index'), value: index),
8);
9

Multi-value Form

1enum Language { dart, java, rust, python }
2
3class SelectTileGroupMultiValueExample extends StatefulWidget {
4 @override
5 State<SelectTileGroupMultiValueExample> createState() =>
6 _SelectTileGroupMultiValueExampleState();
7}
8
9class _SelectTileGroupMultiValueExampleState
10 extends State<SelectTileGroupMultiValueExample> {
11 final _key = GlobalKey<FormState>();
12
13 @override
14 Widget build(BuildContext _) => Form(
15 key: _key,
16 child: Column(
17 mainAxisAlignment: .center,
18 crossAxisAlignment: .start,
19 spacing: 20,
20 children: [
21 FSelectTileGroup<Language>(
22 label: const Text('Favorite Languages'),
23 description: const Text('Your favorite language.'),
24 validator: (values) => (values?.isEmpty ?? true)
25 ? 'Please select at least one language.'
26 : null,
27 children: const [
28 .tile(title: Text('Dart'), value: .dart),
29 .tile(title: Text('Java'), value: .java),
30 .tile(title: Text('Rust'), value: .rust),
31 .tile(title: Text('Python'), value: .python),
32 ],
33 ),
34 FButton(
35 child: const Text('Save'),
36 onPress: () {
37 if (!_key.currentState!.validate()) {
38 // Handle errors here.
39 return;
40 }
41
42 _key.currentState!.save();
43 // Do something.
44 },
45 ),
46 ],
47 ),
48 );
49}
50

Radio Form

1enum Notification { all, direct, nothing }
2
3class SelectTileGroupRadioExample extends StatefulWidget {
4 @override
5 State<SelectTileGroupRadioExample> createState() =>
6 _SelectTileGroupRadioExampleState();
7}
8
9class _SelectTileGroupRadioExampleState
10 extends State<SelectTileGroupRadioExample> {
11 final _key = GlobalKey<FormState>();
12
13 @override
14 Widget build(BuildContext _) => Form(
15 key: _key,
16 child: Column(
17 mainAxisAlignment: .center,
18 crossAxisAlignment: .start,
19 spacing: 20,
20 children: [
21 FSelectTileGroup<Notification>(
22 control: const .managedRadio(),
23 label: const Text('Notifications'),
24 description: const Text('Select the notifications.'),
25 validator: (values) =>
26 values?.isEmpty ?? true ? 'Please select a value.' : null,
27 children: const [
28 .tile(title: Text('All new messages'), value: .all),
29 .tile(title: Text('Direct messages and mentions'), value: .direct),
30 .tile(title: Text('Nothing'), value: .nothing),
31 ],
32 ),
33 FButton(
34 child: const Text('Save'),
35 onPress: () {
36 if (!_key.currentState!.validate()) {
37 // Handle errors here.
38 return;
39 }
40
41 _key.currentState!.save();
42 // Do something.
43 },
44 ),
45 ],
46 ),
47 );
48}
49

Appearance

Custom Icons

1class SelectTileGroupSuffixExample extends StatefulWidget {
2 @override
3 State<SelectTileGroupSuffixExample> createState() =>
4 _SelectTileGroupSuffixExampleState();
5}
6
7class _SelectTileGroupSuffixExampleState
8 extends State<SelectTileGroupSuffixExample> {
9 @override
10 Widget build(BuildContext _) => FSelectTileGroup<String>(
11 control: const .managedRadio(),
12 label: const Text('Settings'),
13 children: const [
14 FSelectTile.suffix(
15 prefix: Icon(FIcons.list),
16 title: Text('List View'),
17 value: 'List',
18 ),
19 FSelectTile.suffix(
20 prefix: Icon(FIcons.layoutGrid),
21 title: Text('Grid View'),
22 value: 'Grid',
23 ),
24 ],
25 );
26}
27

Full Divider

1enum Sidebar { recents, home, applications }
2
3class FullDividerSelectTileGroupExample extends StatelessWidget {
4 @override
5 Widget build(BuildContext _) => FSelectTileGroup<Sidebar>(
6 control: const .managed(initial: {.recents}),
7 label: const Text('Sidebar'),
8 description: const Text('These will be shown in the sidebar.'),
9 divider: .full,
10 children: const [
11 .tile(
12 title: Text('Recents'),
13 suffix: Icon(FIcons.timer),
14 value: .recents,
15 ),
16 .tile(title: Text('Home'), suffix: Icon(FIcons.house), value: .home),
17 .tile(
18 title: Text('Applications'),
19 suffix: Icon(FIcons.appWindowMac),
20 value: .applications,
21 ),
22 ],
23 );
24}
25

No Divider

1enum Sidebar { recents, home, applications }
2
3class NoDividerSelectTileGroupExample extends StatelessWidget {
4 @override
5 Widget build(BuildContext _) => FSelectTileGroup<Sidebar>(
6 control: const .managed(initial: {.recents}),
7 label: const Text('Sidebar'),
8 description: const Text('These will be shown in the sidebar.'),
9 divider: .none,
10 children: const [
11 .tile(
12 title: Text('Recents'),
13 suffix: Icon(FIcons.timer),
14 value: .recents,
15 ),
16 .tile(title: Text('Home'), suffix: Icon(FIcons.house), value: .home),
17 .tile(
18 title: Text('Applications'),
19 suffix: Icon(FIcons.appWindowMac),
20 value: .applications,
21 ),
22 ],
23 );
24}
25

On this page