Theming
The flow_ui token system: three levels of ink, translucent washes on opaque grounds, and a color scheme shaped like Material 3.
Every flow_ui component draws from two token sets — colors and
typography — installed as a ThemeExtension:
MaterialApp( theme: ThemeData(extensions: [FlowTheme.light()]), darkTheme: ThemeData( brightness: Brightness.dark, extensions: [FlowTheme.dark()], ),)No component hardcodes a color or a text style, so restyling the whole library is a matter of overriding tokens.
Three levels of ink
Section titled “Three levels of ink”Color role names follow Material 3’s ColorScheme, so an existing M3 scheme
maps straight across — with one addition. The Flow design draws content at
three strengths, and M3 only names two:
| Token | Strength | Used for |
|---|---|---|
onSurface |
100% | Prose, the model name, an active label |
onSurfaceVariant |
75% | Secondary content: row labels, icons at rest |
onSurfaceMuted |
50% | Muted chrome: placeholders, carets, action icons |
Below the ramp sits onSurfaceDisabled (30%) — not a fourth content level
but the drained state: the send disc with nothing to send.
Two rules hold the palette together
Section titled “Two rules hold the palette together”The ink, the outlines, and the container ladder are translucent.
onSurfaceVariant, onSurfaceMuted, outline (14% ink in light, 20% in
dark) and outlineVariant (6%) are the foreground ink at an alpha, not
resolved colors — the same label and the same hairline read correctly on
the page and on a raised card, because they composite. The
surfaceContainerLowest → Highest ladder is cut from the same ink in even
steps — 2, 4, 6, 8, 10% — so a fill picked for the page holds up anywhere.
The grounds are opaque. surface — warm paper in light, #171717 in
dark — and surfaceBright are what everything else composites onto, so
they are flat colors.
The raised card
Section titled “The raised card”surfaceBright is the composer, the menus, the sheets — the one surface
that lifts off the page in both themes. That’s why it sits outside the
surfaceContainerLowest → Highest tint ladder rather than at the bottom of
it: in light it’s pure white above warm paper, in dark it’s the lifted
#1E1E1E above #171717. (surfaceContainerLowest is the ladder’s
faintest rung — a 2% wash — not the card; retheme the card through
surfaceBright.)
Overriding tokens
Section titled “Overriding tokens”Start from a preset and replace what your brand needs:
MaterialApp( theme: ThemeData( extensions: [ FlowTheme( colors: FlowColors.light.copyWith( primary: const Color(0xFF6750A4), ), ), ], ),)Your own widgets can read the same tokens the components use:
final colors = context.flowColors;final typography = context.flowTypography;
Text( 'Caption', style: typography.bodySmall.copyWith(color: colors.onSurfaceVariant),)The type scale
Section titled “The type scale”FlowTypography.standard follows the Material 3 scale — display, headline,
title, body and label, each in large / medium / small — set in Figtree. Two
habits of the design carry through the whole scale: no letter-spacing, and
one of two line heights — 1.5 where text wraps into paragraphs, 1.3 where
it sits on a single line in a control.
Each body size also carries three weights of ink — bodyLarge,
bodyLargeEmphasised (w500), bodyLargeDark (w600), and likewise for
Medium and Small — so emphasis inside a message never needs an ad-hoc
copyWith. Styles are colorless; components pair them with color tokens at
draw time.
To keep the scale and swap the face:
FlowTheme( colors: FlowColors.light, typography: FlowTypography.standard.withFontFamily('Inter'),)withFontFamily rebuilds every style from the four things the scale
carries — size, weight, line height, tracking — and takes a package: for
a font that ships inside one.
Spacing and radii are not tokens
Section titled “Spacing and radii are not tokens”Following Material’s structure, each component bakes its own metrics from
the design file and exposes per-widget overrides (padding:,
borderRadius:) where hosts retheme. There is deliberately no global
spacing scale to fight with.