Elevation

Shadow tokens for visual elevation and inset state rings.

Overview

Elevation tokens create depth through box-shadow. Three levels (low, med, high) establish a visual hierarchy for floating elements. Inset shadows provide focus and selection rings for interactive components.

Elevation Scale

Each level adds stronger offset and spread. Shadow color adapts to dark mode automatically via light-dark().

TokenPreview
--shadow-low
--shadow-med
--shadow-high
--shadow-inset-hover
--shadow-inset-selected
--shadow-inset-success
--shadow-inset-warning
--shadow-inset-error

The elevation prop

Configurable surfaces expose a single elevation prop instead of asking consumers to hand-write a box-shadow. It takes the graded enum none | low | med | high, narrowed per component to the steps that surface needs: Card, ClickableCard, SelectableCard, Button, IconButton, ButtonGroup, Thumbnail, and Banner expose the full scale, while ChatComposer exposes only none | low. none is a flat literal (box-shadow: none); the other levels map to the --shadow-* tokens above, so a surface stays theme-agnostic.

Prop defaults preserve current appearance: every surface defaults to none except ChatComposer, which defaults to low to keep its raised look. Set elevation="none" to flatten it. Thumbnail keeps its existing hover-only shadow at the none default.

Raising a surface with the elevation prop
tsx
// Flat by default — raise only when the surface needs to float.
<Card elevation="low">Raised card</Card>
// A floating action button.
<IconButton icon={<Icon icon="add" />} label="New" variant="primary" elevation="med" />
// Flatten the composer (defaults to 'low').
<ChatComposer elevation="none" onSubmit={handleSubmit} />

Always float — no prop: intrinsic overlays (Dialog, Popover, Tooltip, Toast, HoverCard, DropdownMenu, and the components that compose them) bake their elevation in and never expose the prop. Flow content (inputs, Text, layout) is never elevated; input fields use inset rings, which are a separate concept from elevation.

Usage

When building a custom surface, read elevation from the token scale rather than a hand-rolled shadow — the same tokens the elevation prop resolves to.

Applying elevation
tsx
import {shadowVars} from '@astryxdesign/core';
const styles = stylex.create({
dropdown: {
boxShadow: shadowVars['--shadow-med'],
},
dialog: {
boxShadow: shadowVars['--shadow-high'],
},
inputFocused: {
boxShadow: shadowVars['--shadow-inset-selected'],
},
});

Best Practices

GuidancePractices
Do

Reach for the elevation prop on a configurable surface before writing any custom shadow.

Do

Match elevation to interaction context: low for tooltips, med for dropdowns, high for dialogs.

Do

Use inset shadows for input focus/selection states; they compose better than outlines.

Don't

Hand-write a box-shadow in app code — set the elevation prop or read shadowVars instead.

Don't

Stack multiple elevation levels on the same element.

Don't

Use elevation shadows for decorative borders. Use --color-border tokens instead.