Ergonomics#
A couple of small helpers remove boilerplate that otherwise gets copy-pasted across a codebase.
cx: joining class names#
cx joins CSS class names into a single space-separated string, skipping null
and blank entries. It replaces the ad-hoc _joinClasses helper that tends to get reinvented at every call site that composes conditional classes.
Source: lib/util/classes.dart
String cx(List<String?> classes);
Pass it to any classes: parameter, mixing always-on classes with conditional ones:
div(
classes: cx(<String?>[
'card',
isActive ? 'is-active' : null,
size,
]),
children,
);
null and whitespace-only entries are dropped, so a false branch simply contributes nothing:
cx(<String?>['btn', disabled ? 'btn-disabled' : null]);
// disabled == false -> 'btn'
// disabled == true -> 'btn btn-disabled'
Semantic tags on Container#
Container renders a div by default, but the tag: parameter lets you emit any semantic HTML element instead —
nav, section, header, main, aside, and so on. This keeps layout code Flutter-shaped while producing meaningful, accessible markup.
Source: lib/component/layout/flow.dart
Container(
tag: 'section',
padding: const EdgeInsets.all(24),
child: const Text.body('Rendered as a <section>, not a <div>.'),
)
Container(
tag: 'nav',
child: navigationLinks,
)
When tag is omitted the output is byte-identical to the previous div-only behavior, so it is a safe, opt-in addition to any existing layout.