Skip to content

Core

Surface hierarchy

Stable

Which surface token to use at each level of a screen, so the page, its content and anything raised above it stay distinct in light and dark.

A screen is built in layers. The page sits at the back, content sits on it, and a few things stand above that. Each layer has its own surface token, so neighbouring layers always contrast, in both themes.

The three levels

LevelTokenUse it for
Base--color-background-surface-neutral-basePage backgrounds that group content, such as settings, search pages and overviews
Default--color-background-surface-neutral-defaultContent-first views, forms, flows, modals and bottom sheets
Elevated--color-background-surface-neutral-elevatedCards, navigation tiles and other things that need to stand out

Base

neutral-base is the background for a page whose content is grouped visually, like utilities. Use it when the page is made of separate blocks, not one continuous piece of content.

  • Settings, for example notification settings
  • Search pages
  • Overviews
  • Navigation

Nesting: default components or pages can be nested inside a base screen background. Content then sits on the base surface in default or elevated containers.

Default

neutral-default is for default views, where the page is content first.

  • Articles and blogs
  • Forms and flows
  • Anything for reading, including rich text
  • Interactive elements
  • Modals, sidebar menus and bottom sheets
  • Primary containers and focused flows

Modals, sidebar menus and bottom sheets always use default, whatever surface is behind them.

Elevated

neutral-elevated is for components that need to stand out from the default background. Use it sparingly. If everything is elevated, nothing stands out.

Avoid elevated backgrounds for large surfaces or full pages. They are reserved for components.

  • Cards
  • Navigation tiles
  • Elevated UI sections

Always pair an elevated surface with a border token, and add a shadow if it needs more lift. In light mode the elevated and default surfaces are the same colour, so the border or shadow is what separates the two layers. Use a border token such as --color-border-soft (see Using borders). If you add a shadow, keep the border: shadows are barely visible in dark mode, so the border is what keeps the layers apart there.

Choosing a level

  1. Start with the page. If it is content first, use default. If it groups separate blocks, use base.
  2. Put ordinary content on the layer above the page: default components or whole pages can sit inside a base screen background.
  3. Raise a component to elevated only when it has to stand out from what is around it, and give it a border token. Add a shadow only on top of a border, never instead of one.
  4. Do not step more than one level at a time. An elevated element sits on default or base, never on another elevated element.

In code

Set the level with the emphasis prop on Surface. Card passes it through to its Surface.

// A settings page: base background, default panel, one elevated tile.
// Card brings its own soft border, which is what separates the elevated layer.
<Surface emphasis="base" className="p-6">
  <Surface className="rounded-lg p-6">
    <Card emphasis="elevated" content="Notification settings" />
  </Surface>
</Surface>

default is the default, so a plain <Surface> is the default level. The same props exist on React Native.

Inverse surfaces have elevated and base as well. Brand surfaces do not, and keep their default background for those values. See Surface for the full emphasis table.

Android

On Android the surface tokens arrive as Material 3 colour roles, from checkatradeLightColorScheme() and checkatradeDarkColorScheme() in com.checkatrade.designsystem:tokens. Read them through MaterialTheme.colorScheme.

LevelTokenCompose roleUse it for
Basesurface-neutral-basebackgroundThe page behind scrollable content: settings, search pages and overviews
Defaultsurface-neutral-defaultsurfaceContent-first screens, modals, sidebar menus and bottom sheets
Elevatedsurface-neutral-elevatedsurfaceBrightComponents that need to stand out, such as cards and navigation tiles

The other neutral tokens map to Material’s container roles: soft to surfaceContainer, strong to surfaceContainerHigh, strongest to surfaceDim, alt to surfaceContainerHighest and pure to surfaceContainerLowest. Use them for the Material components that expect them, not as a substitute for the three levels above. Inverse surfaces map to inverseSurface.

Material’s own sheets, drawers and dialogs default to the container roles, so set their container colour to surface yourself: modals, sidebar menus and bottom sheets always use default. An elevated component still needs a border, and outline is the default border role (see Using borders).

// A settings screen: base page, elevated card with a border
Scaffold(containerColor = MaterialTheme.colorScheme.background) { padding ->
    Card(
        modifier = Modifier.padding(padding),
        colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceBright),
        border = BorderStroke(1.dp, MaterialTheme.colorScheme.outline),
    ) { /* content */ }
}

// A bottom sheet: always default
ModalBottomSheet(
    onDismissRequest = onDismiss,
    containerColor = MaterialTheme.colorScheme.surface,
) { /* content */ }

Examples

Two layouts that use the levels together. The callouts name the surface token for each layer and the ink token for the text on it.

A page on the base surface. The elevated card has a border and a shadow and sits over the brand header; the default card sits below it. The text colour is the ink token for each surface.
An app shell: navigation and header on the default surface, a base content area, and a default panel holding one elevated component with a border.