Surface
A panel, well, and toolbar primitive built from facets and theme levels
Surface is the starting point for panels, wells, and toolbars: a YStack
with a level prop and composable visual and interaction facets.
Nothing is on by default. A bare <Surface /> renders no chrome and no
interaction styling, and every facet is opt-in at the use site.
Features
Plain YStack, level prop, and opt-in facets
Theme-generic facets, automatically restyled across themes and levels
Forkable recipe for app-specific Surface variants
Installation
Surface is already installed in tamagui:
Surface is also a registry item you can copy into your own component layer and own; see Build your own.
Levels
level shifts the subtree through the relative level2, level3, or level4
sub-theme. Because facets read theme generics (background, border-color, …)
and the level theme re-binds those generics, a level restyles every facet
beneath it with no cooperation. Read Surfaces and
levels for the full theming model.
level is a prop, not a variant, because a theme boundary can only be created by
the theme prop or <Theme> component. <Surface level={2}> renders
<Theme name="level2"> around the frame.
Facets
Facets are canonical boolean variants, each a pure function of theme generics plus standard tokens. Chrome facets own one property family each and set static styles only; the interaction facet owns pseudos only. Because family ownership keeps them from colliding, any combination composes with zero coordination.
There are no preset combinations. The Material-style border-minus-fill look is just
outlined without filled: a documented composition, not a separate facet.
Build your own
Most apps just import Surface. Copy it into your own component layer when you want variants of your own: a card panel with different defaults than a toolbar well, your own radius, or facets tuned to your design system. The copy is a plain component: change it freely and nothing in the framework cares.
Copy it from the registry:
yarn
npm
bun
pnpm
That installs components/tamagui/Surface.tsx plus its sibling
components/tamagui/facets.tsx, which holds the shared facet definitions.
Surface.tsx imports them through a relative ./facets import, so keep the two
files together and adjust the path if your tree puts them elsewhere.
Surface is generated from a single definition. The level wrapper and the facet
set are all it is:
The facets live in a sibling facets.tsx so any skin can compose the same chrome:
Component skins like Card and ListItem do not extend Surface. They get their family resemblance by styling against the same generics, so restyling a level recolors them too. Fork the copy when you want a differently-shaped panel.
API reference
Surface
A YStack with a level prop and composable facets, plus all the
Tamagui standard props:
Props
level
1 | 2 | 3 | 4
Shift the subtree through a relative level theme.
filled
boolean
Chrome: backgroundColor from background.
outlined
boolean
Chrome: 1px borderWidth with borderColor from border-color.
elevated
boolean
Chrome: a shadow read from shadow-color.
rounded
boolean
Chrome: the default component radius.
interactive
boolean
Interaction: hover, press, and focus-visible feedback read from the generics (background-hover, background-press, border-color*, and outline-color).