A box that sets content on one step of the surface ladder: glass or an opaque panel floating over the map, a raised card inside a panel, or an inset box, each with its fill, edge, radius, shadow and padding from the tokens.
When to use
Use Surface for a box that only sets content on one step of the surface ladder: a panel floating over the map, a card inside a panel, or a box set into one.
| Use instead | When |
|---|---|
| Dialog | The panel opens over the screen and holds focus until it closes, with Esc and a backdrop |
| Sheet | The panel slides in from the edge of the screen, such as the overview or the detail panel |
| Popover | A small glass panel opens from a button and leaves the rest of the screen usable |
| Section | The content inside a panel needs a small heading, and an action beside it |
| Alert | The box says what is happening and how much it matters, in an intent's tinted colour |
Kongens Nytorv
Metro M1, M2 and M3.
Variants and states
| Rest | |
|---|---|
| Raised | Next train to Lufthavnen in 3 min |
| Inset | Next train to Lufthavnen in 3 min |
| Glass | Next train to Lufthavnen in 3 min |
| Opaque | Next train to Lufthavnen in 3 min |
- RestNext train to Lufthavnen in 3 min
Props
| Name | Type | Default | Description |
|---|---|---|---|
variant | 'raised' | 'inset' | 'glass' | 'opaque' | 'raised' | The step of the surface ladder: raised for a card inside a panel, inset for a box or track set into one, glass for a panel floating over the map, opaque for a floating panel full of text on a phone, where glass would let the map show through. |
children | ReactNode | — | The content the surface holds |
className | string | — | Reaches the root; className is merged after pn-Surface |
style | CSSProperties | — | Reaches the root; className is merged after pn-Surface |
ref | Ref<HTMLElement> | — | Reaches the root element, whichever element render makes it |
variant'raised' | 'inset' | 'glass' | 'opaque', default'raised'- The step of the surface ladder:
raisedfor a card inside a panel,insetfor a box or track set into one,glassfor a panel floating over the map,opaquefor a floating panel full of text on a phone, where glass would let the map show through. childrenReactNode, default —- The content the surface holds
classNamestring, default —- Reaches the root;
classNameis merged afterpn-Surface styleCSSProperties, default —- Reaches the root;
classNameis merged afterpn-Surface refRef<HTMLElement>, default —- Reaches the root element, whichever element
rendermakes it
Use it
import { Surface } from '@mylder/perron'Ask your agent
search_docs({ query: "Surface" })Keyboard and ARIA
Surface is a box: it takes no focus, and no key does anything. Focus moves through the caller's content in reading order. A caller who makes it a link or button through render brings that element's own keys.
| Key | Does | From |
|---|---|---|
| none | Surface is not focusable or operable; Tab reaches its content | Perron |
| Element | Role | Accessible name from | States announced |
|---|---|---|---|
root | none: a generic <div> | Not named. Through render, a <section>, <aside> or <article> takes its name from the caller's heading by aria-labelledby | none |
What axe won't catch, from the contract, each with how this component meets it:
- Everything the eye is told, the ear is told, for every shape each prop accepts: the surface tells the eye only grouping and depth, which the content's own headings and order tell the ear; Surface carries no colour that means a state (no
colorprop). - Every landmark and named region has an accessible name: the root is a generic
<div>and no landmark; a caller who renders it as<section>,<aside>or<article>names it witharia-labelledbypointing at its heading, as theNestedstory shows. - Every default label can be overridden: none here; Surface owns no label.
- Every shape the type accepts renders, in every variant:
childrenas a string, an element and a list all render in each of the four variants, shown by the variant stories. - A hidden copy kept for animation is
aria-hidden, and a collapsed region isinert: none here; Surface does not animate or collapse. - Native semantics first: a
<div>with no role and no ARIA; the caller picks<section>,<aside>or<article>throughrenderwhen the box is a region. - Focus moves in reading order and returns on close: Surface takes no focus and does not reorder its content; it does not clip, so a focused child's ring shows in full (CR-4).
- Every target is at least
size.target-minsquare: no target; Surface is not pressed. - Loops stop when the system asks for less motion: none here; Surface has no motion.
Owned strings
No owned strings: Surface shows and announces no words of its own; every word inside it is the caller's.
Do and don't
For a caller using the component, with the reason. Each row is a rule: a must row's Don't is never right, a should row's needs a reason, and Checked by says what catches the Don't in a caller's code.
| Rule | Level | Do | Don't | Checked by |
|---|---|---|---|---|
| DD-1 | should | Use glass for a panel that floats over the map, and opaque for one full of text on a phone, as Elevation says. | Use glass over a plain background or inside another panel: the blur has nothing to soften, and glass on glass loses its edge. | review |
| DD-2 | should | Put raised cards and inset boxes inside a panel, stepping down the ladder. | Nest a floating glass or opaque surface inside another surface, or add a shadow to a card with className: only floating panels cast one. | review |
| DD-3 | should | Render it as <section> or <aside> with aria-labelledby on its heading when the box is a region someone navigates to. | Give every card a landmark element: a screen of unnamed regions is noisier than plain boxes. | review |
| DD-4 | must | Use Dialog or Sheet for a panel that opens and closes over the screen, since they bring the focus, Esc and scrim. | Build a dialog from a glass Surface: it would look right and trap no focus. | review |
| DD-5 | must | Say a state in words or with an icon inside the surface. | Tint a surface with a status colour through className to mean warning or success: colour is never alone. | review |
| DD-6 | should | Change the padding through className with a space.* token when rows must run to the edge. | Set raw pixel padding, radius or colours on it, which leave the ladder and the themes behind. | review |