Conditional styling
Apply styles only in a state — hover, focus, pressed, disabled — and propagate state to descendants and siblings with groups and peers.
The accumulator resolves lazily against the active interaction states, so state variants are first-class — the same idea as Tailwind's hover, focus & other states. Each variant takes a builder that receives the current style and returns a modified one — it layers over the base (and still follows last-wins).
Interaction states
final t = context.fw;
const Text('Hover me')
.tw
.px(4)
.py(2)
.rounded(t.radii.md)
.bg(t.colors.secondary)
.text(t.colors.secondaryForeground)
.hover((s) => s.bg(t.colors.primary).text(t.colors.primaryForeground));| flutterwindcss | Tailwind |
|---|---|
hover((s) => …) | hover: |
focus((s) => …) | focus: |
pressed((s) => …) | active: |
disabled((s) => …) | disabled: |
Material-free, by design
On a plain styled box these states are sourced from the widgets layer (a MouseRegion for hover, a
non-traversable Focus, a Listener for press) — there's no Material ink or extra tab stop. A
truly interactive component that owns focus + keyboard activation (a button, say) belongs to the
flutterbits component layer.
Component-managed states
For states your component owns — selected, error, a custom toggle — use
whenState(WidgetState.selected, (s) => …). It's inert until the state is injected (the styled box
takes a states set), so a component drives its own styling without faking pointer events. The
built-in hover/focus/pressed/disabled are just the auto-sourced cases of this.
Groups — react to an ancestor's state
Flutter has no CSS :hover that descendants can read, so flutterwindcss makes the scope explicit.
Wrap a subtree in FwGroup; it sources its own hover/focus/pressed and broadcasts them, and
descendants opt in with groupHover / groupFocus / groupPressed:
FwGroup(
child: FwColumn(
gap: 1,
children: [
const Text('Card title').tw.weight(600).text(t.colors.cardForeground),
// Brightens when the whole card is hovered — not just this text.
const Text('Hover anywhere on the card')
.tw
.text(t.colors.mutedForeground)
.groupHover((s) => s.text(t.colors.foreground)),
],
).tw.p(4).bg(t.colors.card).rounded(t.radii.lg).border(1, color: t.colors.border),
);| flutterwindcss | Tailwind |
|---|---|
FwGroup + groupHover((s) => …) | group + group-hover: |
FwPeer + peerHover((s) => …) | peer + peer-hover: |
Peers — react to a sibling's state
Since Flutter has no DOM sibling selectors, a "peer" relationship is an explicit shared scope: an
FwPeer sources state and its siblings react with peerHover / peerFocus / …. When you nest
groups or peers, disambiguate with a name (groupHover(…, name: 'card'), like Tailwind's
group/card + group-hover/card:).
Next steps
Fonts
How to wire the fonts a generated theme.dart names — bundle them or use google_fonts. flutterwindcss applies the theme's families automatically; you only register the font.
Breakpoints & responsive
Mobile-first responsive variants by screen width (sm/md/lg/xl) and by container width (containerSm…) — two distinct axes.