Surfaces & Levels
Re-bind semantic theme values relative to the current subtree
Surfaces group UI elements into visual containers, and levels adjust the contrast of semantic color tokens relative to their parent container.
What they are
A surface is a container in your layout, such as a panel, card, dialog, or toolbar, with its own background and border.
A level is a relative theme step (level2, level3, level4). It shifts
semantic values like background, border-color, and color one or more
steps from the surrounding theme. In v3, levels are how surfaces get their
contrast. There is no separate surface theme system.
Use a level when a container should stand out from what’s around it. Components inside it read the shifted values, so they adapt without extra color props:
The card resolves background and border-color at level 2. Button reads its
colors relative to that, so it still stands out against the card.
Two color vocabularies
Keep adaptive scale values and semantic styling values separate:
color-1throughcolor-11are the scheme-relative palette ramp. These are theme steps rather than absolute color shades.background,background-hover,background-press,border-color,color, and other generics describe a component’s role.
Component skins should normally use the generics. A level re-binds those keys once for the whole subtree, so every skin below it responds without needing its own color calculations.
Levels are relative sub-themes
Use level2, level3, or level4 to raise a subtree from its current level:
The level name represents an operation rather than an absolute destination. From the root, theme="level2" resolves to absolute level 2. Inside that subtree, another theme="level2" resolves to absolute level 3. theme="level3" moves two steps from the current context. Values clamp at level 4.
The generated path records the nesting, such as light_level2_level2. Saturated paths are aliases of an existing map, so they do not duplicate CSS declarations.
Color themes keep their palette while levels compose:
Surface is a copied panel fixture
For layout surfaces, copy the Surface fixture. It is a YStack
with a level prop and composable filled, outlined, elevated, rounded,
and interactive facets. Nothing is enabled by default:
The level={2} prop creates a level2 theme boundary. The facets read the
semantic generics, so changing the level or surrounding color theme restyles
them together.
Component skins do not extend Surface. Card, Select content, ListItem, and other skins use the same generic values and choose their own default level.
Inline theme values for one-off overrides
Set the value with ThemeUpdate when a patch belongs in exactly one place:
Create a named theme when the same patch appears in multiple places. Set it
inline with ThemeUpdate when it is local to one component.
Custom levels
The defaults are ordinary data in @tamagui/themes/builder. Change a level by
editing or replacing its scale:
levels(max) creates the recursive tree definitions. It works with custom
recipes because it only reads and updates the optional level field.
V2 surface migration
In Tamagui v2, surface names represented fixed templates. Replace them with relative levels in v3:
| V2 theme | V3 theme |
|---|---|
surface1 | level2 |
surface2 | level3 |
surface3 | level4 |
surface4 | level4 |
- V2 theme
surface1- V3 theme
level2- V2 theme
surface2- V3 theme
level3- V2 theme
surface3- V3 theme
level4- V2 theme
surface4- V3 theme
level4
surface4 clamps because the default v3 scale has four absolute levels. If the old contrast was important, add another level to your own scale and tree.
Summary
- Style reusable skins against semantic generics.
- Use
theme="level2"for the common one-step relative boundary. - Nest levels freely because the recipe tree tracks the current absolute level.
- Set the value on
ThemeUpdatefor a one-off patch. - Use the copied Surface fixture for layout chrome.
- Customize scales and
levels()in normal application code.