Surface

Updated: Sep 24, 2026
Use Surface for lower-priority interactive content that needs a secondary surface treatment. It builds on InteractableBase and adds a semantic corner radius, a flat background fill, and stacked inner-shadow overlays for focus and press feedback. The toolkit owns those interaction visuals so focus and activation remain consistent. Surface does not render a ContainerMaterial, use a shape provider, or draw smooth corners.
Prefer Container for primary interactive content, StaticContainer for non-interactive material rendering, and Panel for an informational backdrop. Surface is typically needed only when those components do not express the intended secondary interaction. Follow the same supported-composition boundaries as Container, and use the large spacing token around non-full-bleed content.

Usage

Surface is interactive by default. A plain instance receives focus, shows press feedback, and activates as a control:
import {Surface, SurfaceCornerRadius, TextView, TextStyle} from '@wearables-ui-toolkit/mrbd';

function SecondaryDetails() {
  return (
    <Surface
      cornerRadius={SurfaceCornerRadius.MEDIUM}
      ariaLabel="Secondary details"
      onActivate={openSecondaryDetails}
    >
      <TextView className="surface-content" textStyle={TextStyle.BODY1}>
        Secondary details
      </TextView>
    </Surface>
  );
}
.surface-content {
  padding: var(--uit-spacing-large);
}
For a surface that only groups static content, prefer StaticContainer or Panel. When the visual treatment specifically requires Surface, set interactive={false} so it does not enter focus or directional navigation:
import {Surface, SurfaceCornerRadius} from '@wearables-ui-toolkit/mrbd';

<Surface
  interactive={false}
  cornerRadius={SurfaceCornerRadius.SMALL}
  drawBackground={false}
>
  <PreviewMedia />
</Surface>;

Props

Surface renders a div and forwards its ref to that element. In addition to its own props, it accepts the complete InteractableBase prop surface, including capability switches, activation callbacks, tooltip props, partial-focus props, and standard DOM attributes. The toolkit forwards these to the root. The full prop type is SurfaceProps.

Own props

PropTypeDefaultDescription
children
ReactNode
—
Content rendered in a centered wrapper that fills the surface.
cornerRadius
SurfaceCornerRadius
SurfaceCornerRadius.XSMALL
Semantic corner radius. Bare numbers are not accepted.
drawBackground
boolean
true
Renders the background fill layer.
width
number \| string
'auto'
CSS width. A number is treated as pixels; prefer intrinsic or responsive values.
height
number \| string
'auto'
CSS height, with the same rules as width.
contentScaleForStateFn
(state, size) => number
app platform profile
Overrides the content-scale policy.
className
string
''
Class added alongside the component’s root class.
style
CSSProperties
—
Inline styles merged over the surface’s root styles. They can override size, radius, opacity, and transform.

Notable inherited props

PropTypeDefaultDescription
interactive
boolean
true
Master switch for focusable, pressable, and clickable. Set it to false for a visual-only surface.
focusable
boolean
value of interactive
Controls whether the surface receives focus.
pressable
boolean
value of interactive
Controls whether the surface shows press feedback.
clickable
boolean
value of interactive
Controls whether activation runs.
disabled
boolean
false
Blocks activation and applies disabled opacity while keeping the surface focusable.
onActivate
(event: InteractableActivationEvent) => void
—
Runs once per activation.
onStateChange
(prev: InteractionState, next: InteractionState) => void
—
Runs after Surface applies its own state change.
ariaLabel
string
—
Accessible name.
role
string
'button' when clickable
Overrides the role when the surface is not a button.
tooltipMode
TooltipMode
TooltipMode.NONE
Enables the tooltip. Other tooltip* props behave as documented on the base.

Types and enums

SurfaceCornerRadius

SurfaceCornerRadius is a closed set of semantic radii from smallest to largest. Bare numbers are not assignable, which keeps every surface on the same shape scale instead of creating per-instance radii.
MemberValue
SurfaceCornerRadius.XXSMALL
'xxsmall'
SurfaceCornerRadius.XSMALL
'xsmall'
SurfaceCornerRadius.SMALL
'small'
SurfaceCornerRadius.MEDIUM
'medium'
SurfaceCornerRadius.LARGE
'large'
SurfaceCornerRadius.XLARGE
'xlarge'
These cases are the first six steps in the shared corner radius scale. Matching a surface and an adjacent material-backed component to the same step gives them a consistent shape.

Behavior

  • Interactive by default.Surface inherits the default interactive behavior. A bare instance is focusable, pressable, and clickable, and its div root receives the button role. Set interactive={false} for a static surface so it does not advertise control behavior.
  • Layers. The toolkit paints a background fill below the content and two inner-shadow overlays above it. The focused overlay fades in on focus and remains through press. The pressed overlay fades in above it, making press feedback stronger than focus feedback. All three layers are decorative and hidden from assistive technology. drawBackground={false} removes only the fill; the inner shadows continue to respond to interaction state.
  • Content scale. As with Container, Surface reads the platform profile supplied by App and scales the whole surface slightly inward at rest, opens it to full size on focus, and insets it again on press. Applications do not pass a platform value to individual surfaces. The scale comes from an explicit numeric width when present, otherwise from the measured width. Until the toolkit knows the real size, the surface remains at full size instead of estimating.
  • Measurement never animates. The toolkit applies scale changes caused by first layout, font settling, or resize immediately. Only interaction-state changes animate. The same duration and easing drive scale and inner-shadow opacity so the visuals settle together.
  • Timing follows the transition. Press-in and press-out transitions use their own short durations and curves. A focus change during rapid focus movement uses a shorter duration so movement through a list settles instead of trailing behind. Every other state change uses the standard duration.
  • Corner radius and clipping. The toolkit resolves cornerRadius to a semantic token and applies the resulting plain CSS radius to the root, fill, and both inner shadows. The root clips its content, so the surface rounds full-bleed children consistently.
  • Disabled. The toolkit changes the root from var(--uit-enabled-opacity) to var(--uit-disabled-opacity) and blocks activation. The element remains focusable so directional navigation preserves its layout structure.
  • Sizing. The inline-flex root hugs its content unless width or height provides another size. Its content wrapper centers children on both axes. The toolkit writes size, radius, opacity, and content-scale transform inline, so a CSS class cannot change them; use the corresponding props or style.
  • No material.Surface has no material or shapeProvider prop, smooth corner path, or partial-focus material origin. Prefer Container when the design requires material behavior.

Accessibility

A clickable Surface renders as a div with role="button" and a tab index. It activates on click and with Enter or Space. Provide an ariaLabel when visible content does not already name the action, so assistive technology exposes a clear target.
The root element is always a div; callers cannot replace it with a built-in HTML element. When the surface represents something other than a button, the application must set the correct role and provide every ARIA state required by that role. For content that only needs visual grouping, set interactive={false} so the surface leaves directional navigation and exposes no control role.
The toolkit marks the background and inner-shadow layers aria-hidden, keeping these decorative visuals out of the accessibility tree.
  • Use Surface for lower-priority interactive content that specifically needs a secondary surface treatment.
  • Choose a semantic SurfaceCornerRadius value and semantic spacing tokens for its content so shape and rhythm remain consistent.
  • Keep one coherent interaction target in each surface.
  • Set interactive={false} when the surface is visual rather than a control, so it does not create a misleading focus stop.

Unsupported compositions

  • Prefer Container or a higher-level component whenever it already expresses the intended interface and behavior.
  • For static grouping, prefer StaticContainer or Panel; otherwise set interactive={false} explicitly.
  • Do not nest material-owning components or intrinsic controls inside Surface. These components each own their focus, interaction, or surface behavior, so the composition is unsupported.
  • Treat Surface as a flat secondary treatment. It has no shape provider, smooth corners, or partial-focus material response; use Container for those capabilities.
  • Avoid overriding style with a radius outside the semantic cases. Choose a supported SurfaceCornerRadius so adjacent surfaces remain consistent.