Theming¶
Install both canonical token sets on MaterialApp:
MaterialApp(
theme: TsaiTheme.light(),
darkTheme: TsaiTheme.dark(),
themeMode: ThemeMode.system,
home: const HomeScreen(),
);
TsaiTheme.light and TsaiTheme.dark accept an existing ThemeData through
base. Unrelated theme extensions are preserved:
final lightTheme = TsaiTheme.light(
base: ThemeData(
useMaterial3: true,
visualDensity: VisualDensity.standard,
),
);
Read semantic values inside a custom widget with:
final tokens = TsaiThemeTokens.of(context);
return ColoredBox(
color: tokens.colors.surfaceRaised,
child: Padding(
padding: EdgeInsets.all(tokens.spacing.space16),
child: Text(
'Account',
style: tokens.typography.bodyLarge,
),
),
);
Reusable Penpot scrim assets are exposed through the typed gradient group:
DecoratedBox(
decoration: BoxDecoration(
gradient: tokens.gradients.bottomScrim,
),
child: content,
);
topScrim and bottomScrim resolve to their light or dark Penpot asset with
the active TsaiTheme. Backdrop effects such as glass surfaces read
tokens.effects.glassBlur; applications creating a complete custom token set
must provide every color, gradient, and effect role.
Nested surfaces inside a medium-radius container use
tokens.radii.innerMedium rather than deriving a radius from spacing values.
Buttons also support application-wide variant overrides through
TsaiButtonTheme. Keep overrides semantic and test them in both brightness
modes.
Accessibility¶
Do not disable text scaling. Supply semanticLabel when the visible label is
ambiguous, and use the loading/error semantics exposed by each component.
Tsai controls preserve keyboard focus and honor the platform reduced-motion
preference.