Surfaces
The background/elevation treatment everything else in the system sits on top of. Use to establish depth and visual hierarchy between page background, cards, and floating content. Don't use as a substitute for spacing or container tokens.
FigmaDescription
Surfaces are the set of background treatments — default, raised, lowered, and inverse — that establish depth and visual hierarchy across the product. Every other component (buttons, inputs, containers, modals) is drawn on top of a surface, and which surface it sits on determines its border, elevation, and contrast requirements.
Everywhere. The page background is a surface. A card floating above the page is a raised surface. A recessed input well or code block is a lowered surface. A tooltip or high-contrast callout may use an inverse surface.
Without a shared surface model, every component ends up hand-rolling its own background/border logic, and elevation stops meaning anything consistent. Surfaces give the system one small, shared vocabulary — four levels, not an open-ended set of custom backgrounds — that every other component's tokens (Component.Base, per-brand aliases) build on top of.
Consumed directly by the Colors token collection (Colors.Light.tokens.json / Colors.Dark.tokens.json, Surface group) — see Style tab for the resolved values in both themes. Every container-like component (Containers, Modal, Card, Popover) should reference these tokens rather than hardcoding a background.
Anatomy
| Part | Required? | Notes |
|---|---|---|
| Surface fill | Required | The background colour itself — one of Default, Raised, Lowered, or Inverse. |
| Surface border | Optional | The paired border colour for that surface level, used when background contrast alone doesn't define the boundary (e.g. Default-on-Default nesting). |
| On-surface content | Required | Text, icon, and interactive-element colours are chosen relative to the surface they sit on, not globally — the same text token can fail contrast on Inverse where it passes on Default. |
Variants
Default
The baseline page/contained-background surface.
The starting surface for a page or panel. Most content lives here.
Raised
Positioned closest to the user — a surface that sits visually above Default.
Cards, popovers, dropdown panels, anything meant to read as floating above the page.
Lowered
Positioned farthest from the user — a surface that sits visually below Default.
Recessed wells — an input's own background, a code block, a nested "sunken" region within a container.
Inverse
A surface that flips the relationship between foreground and background.
High-emphasis callouts, tooltips, and any moment that needs to visually break from the surrounding surface stack.
States
| State | Behaviour |
|---|---|
| Light theme | Default and Lowered currently resolve to the same token value in Light — see Style tab. Raised is a step lighter. |
| Dark theme | Default and Raised currently resolve to distinct neutral steps; Inverse flips to a near-white neutral, the mirror of Light's near-black Inverse. |
Usage guidelines
When to use
- Any time a component needs a background — reach for one of the four surface tokens rather than a one-off colour.
- Establishing depth between a page and the floating content above it (modals, popovers, dropdowns).
- Recessing a region to read as "inside" or "behind" the surrounding content (input wells, code blocks).
When not to use
- Don't invent a fifth surface level for a one-off design need — that's exactly the drift this token group exists to prevent. Raise it with the DS Working Group instead.
- Don't use Inverse purely for visual variety — it changes the entire on-surface contrast contract, so reserve it for moments that genuinely need to break from the surrounding stack.
Do / Don't
Do
Pick a component's background from Surface tokens, not a hardcoded hex value or an unrelated Primitive.
Don't
Don't reference a Primitive colour (e.g. color-neutral-10) directly in component CSS — go through the Surface (or component-level WA-native) token so a future palette change propagates.
Do
Treat Raised/Lowered as relative to their immediate parent surface, not as absolute z-index levels.
Don't
Don't stack Raised-on-Raised-on-Raised expecting each to read as progressively more elevated — the model has four levels, not infinite depth.
Layout & Spacing
Surfaces are a colour concept, not a spacing one — they carry no dimensional tokens of their own. Pair with Containers' padding/radius tokens for the actual box model.
Tokens
| Part | Token | Value |
|---|---|---|
--wa-color-surface-default | ||
--wa-color-surface-raised | ||
--wa-color-surface-lowered | ||
--wa-color-surface-inverse | ||
--wa-color-surface-border |
Engineering notes
- There is no
wa-surfaceelement — Surface tokens are consumed as background-colour custom properties by whatever component needs them, the same way Containers does. - Reference the WA-native custom property (
--wa-color-surface-*) from component code, not the raw Semantic or Primitive token — that's the same Component-vs-Semantic split documented on the Containers and token architecture pages. - When adding a new container-like component, check this page first before introducing a new background token.
Focus
Surfaces themselves carry no focus behaviour — they're a background concept. Focus-ring contrast against whichever surface a component sits on is that component's own responsibility.
Contrast
Contrast ratios for text/icons on each surface are the responsibility of the component consuming that surface (see each component's own Accessibility tab) — this page doesn't re-verify them independently since the same text token behaves differently depending on which surface it lands on.
Touch targets
Not applicable — surfaces have no interactive affordance on their own.
Things to avoid
- Don't assume a contrast pass on Default automatically holds on Inverse or Raised — re-check per surface.