Surface
Surface
Color, content color, shape, and elevation stay theme-backed.
Tonal elevation (color="surface")
Color roles
Shapes
Shadow elevation
Landmark elements (as)
import type { CSSProperties } from 'react'
import { Surface } from '@language-lit/material3-expressive'
const surfaceColors = [
'surface',
'surface-dim',
'surface-bright',
'surface-container-lowest',
'surface-container',
'surface-container-high',
'surface-container-highest',
'primary',
'primary-fixed',
'primary-fixed-dim',
'secondary',
'secondary-container',
'secondary-fixed',
'secondary-fixed-dim',
'tertiary',
'tertiary-container',
'tertiary-fixed',
'tertiary-fixed-dim',
'error',
'error-container',
'inverse-surface',
] as const
const surfaceShapes = [
'none',
'extra-small',
'extra-small-top',
'small',
'medium',
'large-start',
'large-end',
'large-top',
'large-increased',
'extra-large-top',
'extra-large-increased',
'extra-extra-large',
'full',
] as const
const shadowElevations = [0, 1, 2, 3, 4, 5] as const
const tonalElevations = [1, 2, 3, 4, 5] as const
const surfaceElements = ['article', 'aside', 'header', 'footer', 'nav', 'main'] as const
const swatchGridStyle: CSSProperties = {
display: 'grid',
gap: '0.75rem',
gridTemplateColumns: 'repeat(auto-fill, minmax(9rem, 1fr))',
}
const swatchStyle: CSSProperties = {
display: 'grid',
gap: '0.25rem',
fontSize: '0.75rem',
padding: '0.75rem',
}
export function SurfaceExample() {
return (
<Surface
as="section"
aria-labelledby="surface-example-title"
color="surface-container-low"
shape="extra-large"
className="surface-example"
>
<h2 id="surface-example-title">Surface</h2>
<p>Color, content color, shape, and elevation stay theme-backed.</p>
<Surface
color="primary-container"
shape="large"
shadowElevation={1}
className="surface-example__nested"
>
Nested semantic content
</Surface>
<h3>Tonal elevation (color="surface")</h3>
<div style={swatchGridStyle}>
<Surface color="surface" shape="small" style={swatchStyle}>
Tonal 0 (default)
</Surface>
{tonalElevations.map((level) => (
<Surface key={level} color="surface" tonalElevation={level} shape="small" style={swatchStyle}>
Tonal {level}
</Surface>
))}
</div>
<h3>Color roles</h3>
<div style={swatchGridStyle}>
{surfaceColors.map((color) => (
<Surface key={color} color={color} shape="small" style={swatchStyle}>
{color}
</Surface>
))}
</div>
<h3>Shapes</h3>
<div style={swatchGridStyle}>
{surfaceShapes.map((shape) => (
<Surface key={shape} color="surface-container" shape={shape} style={swatchStyle}>
{shape}
</Surface>
))}
</div>
<h3>Shadow elevation</h3>
<div style={swatchGridStyle}>
{shadowElevations.map((level) => (
<Surface
key={level}
color="surface-container-low"
shadowElevation={level}
shape="small"
style={swatchStyle}
>
Shadow {level}
</Surface>
))}
</div>
<h3>Landmark elements (as)</h3>
<div style={swatchGridStyle}>
{surfaceElements.map((element) => (
<Surface key={element} as={element} color="surface-container" shape="small" style={swatchStyle}>
{`<${element}>`}
</Surface>
))}
</div>
</Surface>
)
}Surface is the passive Material container foundation. It applies a semantic
container/content color pair, shape clipping, tonal elevation, and shadow
elevation without creating interaction behavior.
import { Surface } from '@language-lit/material3-expressive'
import '@language-lit/material3-expressive/styles.css'
<Surface
as="section"
aria-labelledby="account-heading"
color="surface-container-low"
shape="extra-large"
shadowElevation={1}
>
<h2 id="account-heading">Account</h2>
<p>Profile and security settings.</p>
</Surface>Contract
asdefaults todivand accepts onlydiv,section,article,aside,main,header,footer, ornav. The selected element controls semantics; Surface never adds a role.colordefaults tosurface. Surface-container roles useonSurface; accent, error, fixed, and inverse roles select their corresponding Material content role.shapedefaults tononeand exposes all current system corner roles. Start and end shapes swap under RTL.tonalElevationandshadowElevationindependently accept levels0through5. Tonal elevation affects only the basesurfacerole. Shadow elevation is visual and never changes CSS stacking order. Development builds warn when a nonzero tonal level is paired with a color role it cannot affect.- Native attributes, ARIA/data attributes, styles, classes, handlers, children, and a correctly narrowed ref are forwarded to the selected element.
Surface is deliberately non-interactive. Use the later purpose-built Button,
Card, or selection components for click, keyboard, disabled, selected, or
checked behavior. Attaching a click handler to a passive container does not make
it keyboard accessible.
Color roles
Supported roles are the surface family (surface, surface-dim,
surface-bright, and the five surface-container-* emphases), primary,
secondary, and tertiary base/container/fixed roles, error, error-container,
and inverse-surface. Fixed-dim roles use the corresponding high-emphasis
on*Fixed content color; lower-emphasis content can choose its own color in a
descendant.
Tokens
The default component variables are:
--m3e-comp-surface-container-color--m3e-comp-surface-content-color--m3e-comp-surface-container-shape--m3e-comp-surface-container-shadow--m3e-comp-surface-tonal-overlay-opacity
Explicit variants resolve through --m3e-sys-color-*,
--m3e-sys-shape-corner-*, and --m3e-sys-elevation-*. Override the system
theme for a coordinated design system; override the registered Surface component
tokens only when changing the unconfigured Surface defaults.
Accessibility and adaptation
Surface introduces no focus stop, keyboard behavior, accessible state, or interactive role. Landmark naming and document-outline correctness remain with the consumer because they depend on page context. It has no motion, and it does not opt out of browser forced-color adjustment.
On the web, authored CSS clips children and projects shadows. Unlike Android Compose, discrete tonal levels are not accumulated through nested runtime composition locals; nested surfaces should select an explicit surface-container role or tonal level. This keeps styling static, SSR-safe, and responsive to scoped CSS theme overrides.