Carbide styling is entirely token-driven. A CarbonThemeData resolves Carbon's
semantic tokens (background, text, layer, field, border, support, …) onto the
raw palette for one theme; components read those tokens through CarbonTheme.
Carbon defines four themes, two light and two dark. Each is a named constructor
on CarbonThemeData:
| Theme | Brightness | Constructor |
|---|---|---|
| White | light | CarbonThemeData.white |
| Gray 10 | light | CarbonThemeData.gray10 |
| Gray 90 | dark | CarbonThemeData.gray90 |
| Gray 100 | dark | CarbonThemeData.gray100 |
All four expose the same token names, so a component written against the tokens looks correct in every theme without change.
CarbonTheme(
data: CarbonThemeData.gray100,
child: const MyApp(),
);final theme = CarbonTheme.of(context);
final bg = theme.background; // page background
final text = theme.textPrimary; // primary text colorUse CarbonTheme.maybeOf(context) when a theme may be absent. The full token
set is documented on CarbonThemeData in the API reference.
AnimatedCarbonTheme is an implicitly-animated CarbonTheme: when its data
changes it lerps every token to the new theme over the given duration, so a
light↔dark switch crossfades instead of snapping.
AnimatedCarbonTheme(
data: isDark ? CarbonThemeData.gray100 : CarbonThemeData.white,
duration: const Duration(milliseconds: 150),
curve: Curves.easeInOut,
child: const MyApp(),
);Drive isDark from whatever state you keep (a ValueNotifier, a
ChangeNotifier, etc.) and rebuild — the animation is automatic.
Carbon's contextual layering model keeps stacked surfaces — a card on the page,
a card inside that card, a modal over content — visually distinct. Each layer
re-points the contextual tokens (layer, field, the subtle borders, and their
hover/active/selected variants) one step further from the page background.
Wrap a subtree in CarbonLayer to move it up one layer:
CarbonLayer(
child: MyCard(),
);Layers are numbered CarbonLayer.minLevel (0, the implicit level of root
content) through CarbonLayer.maxLevel (2) — Carbon's layer-01 through
layer-03. Nesting beyond the maximum simply stays at the top layer.
- Increment (default):
CarbonLayer(child: …)steps one level up from the ancestor. - Explicit level:
CarbonLayer(level: 2, child: …)pins a specific level. - Paint the background:
CarbonLayer(withBackground: true, child: …)fills the layer'slayerBackgroundtoken behind the child, matching the upstreamwithBackgroundbehavior.
Inside a CarbonLayer, resolve the layer-aware tokens with CarbonLayer.of:
final tokens = CarbonLayer.of(context);
return ColoredBox(color: tokens.layer, child: ...);CarbonLayer.levelOf(context) returns just the current level (without resolving
tokens), which is minLevel when there is no CarbonLayer ancestor.
- Getting started
- Architecture — how foundations, theme, and components layer up internally.