Surface
A copy-paste panel, well, and toolbar primitive built from facets and theme levels
Surface is a copy-paste YStack recipe with relative theme levels and
composable visual or 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
Copy-paste fixture for app-specific Surface variants
Installation
Surface ships with tamagui:
Or copy it into your own component layer from the registry, which is the intended way to own and fork it:
yarn
npm
bun
pnpm
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.
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).
There are no preset combinations. The Material-style border-minus-fill look is just
outlined without filled: a documented composition, not a separate facet.
Copied source
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.
Source
Surface: a copied panel/well/toolbar fixture with composable chrome and interaction facets plus a relative `level` theme boundary. Nothing is on by default; every facet is opt-in. This is the exact source the registry ships — copy it into your app and the examples above import from your copy.
components/tamagui/Surface.tsxAlso copy
components/tamagui/facets.tsx (registry item "facets", via "surface")
Dependencies
yarn add @tamagui/core @tamagui/stacksExpects theme tokens: background, background-hover, background-press, border-color, border-color-hover, border-color-press, shadow-color, outline-color.
Need raw behavior without any skin? tamagui/unstyled re-exports the @tamagui/ui primitives (advanced).