On this page
Import
import {
isPlaceholder,
placeholders,
Surface,
useSkeleton,
} from '@envsemble/envui';
Usage
A Surface gives its content a background, an inset and corners.
- Lay out what it holds through
render, with a Column or a Row, so the surface and its layout are one element. renderalso gives it its meaning, such asrender={<section />}, andrefreaches the rendered element.
import { useId } from 'react';
import { Column, Surface, Text } from '@envsemble/envui';
export default function DetailPane() {
const heading = useId();
return (
<Surface padding={5} render={<Column render={<section />} gap={3} aria-labelledby={heading} />}>
<Text render={<h3 />} variant="title" id={heading}>
Northwind launch
</Text>
<Text>Shared plans, notes and decisions for the spring launch.</Text>
<Text variant="body-sm">Updated by Priya Shah</Text>
</Surface>
);
}Backgrounds, corners and inset
backgroundisdefault, the default,muted,page,raisedorrecessed. In every theme the page and the recessed well lie belowdefault, andmutedandraiseda step above it, with one fill; the recessed well is a shade deeper than the page in dark, and between the page and the panes in light, where it takes the panes' fill at high contrast.radiusisxl, 1.75 rem and the default,sm, 0.5 rem,full, fully rounded ends, ornone, square.paddingsets the inset as a step of the spacing scale, from1, 0.25 rem, to9, 4 rem, and0removes it; without it, the inset grows from 1.25 rem in narrow windows to 1.5 rem from 50 rem wide.
A group of controls, as wide as its controls in a Column with align="start":
<Surface
padding={1}
radius="full"
role="group"
aria-label="Diagram view"
render={<Row wrap align="center" gap={4} />}
>
<IconButton variant="ghost" size="sm" icon={<IconZoomOut />} aria-label="Zoom out" />
<IconButton variant="ghost" size="sm" icon={<IconZoomIn />} aria-label="Zoom in" />
<Button variant="secondary" size="sm">
Fit to screen
</Button>
</Surface>
Loading
skeleton shows the surface and everything inside it as a skeleton until its content arrives: text becomes bars of its text style's length, and controls filled shapes.
- Render the same components over stand-in items,
items ?? placeholders<Project>(3), whose fields are undefined;isPlaceholder(item)tells a stand-in by its id, and narrows the type, so the other branch reads the item's own fields. - A component of the application's own reads
useSkeleton()to give its skeleton a look of its own, such as a chart's.
// A detail pane that is a skeleton until its project arrives: the text it will hold is bars.
<Surface skeleton={!project} style={{ inlineSize: '22rem' }}>
<Column gap={3}>
<Text render={<h3 />} variant="title">
{project?.name}
</Text>
<Text>{project?.brief}</Text>
</Column>
</Surface>
Customize
- To recolor an area, its controls included, set the semantic tokens on a nested Theme, as Customize and extend shows.
- CSS may target
env-surface, withdata-backgroundanddata-radiusfor the values other than the defaults.
Accessibility
You provide
- A heading for a surface that is a region, and its name, such as
aria-labelledbyon a section. role="group"and anaria-labelon a group of controls; a Toolbar for one the arrow keys move through.
envUI provides
- A
divwith no role of its own, or the element inrender, such asrender={<section />}.
Props
Surface
A container with a background, an inset and corners, but no layout of its own: spacing between its children, alignment and behavior come from what it holds, such as a Column. Card and other containers build on it.
| Prop | Type | Description |
|---|---|---|
backgroundDefault 'default' | 'default''muted''page''raised''recessed' | The fill: default, the background of panes and side regions; muted, the background of rows; page, the page background; raised, a block that stands out on a pane; or recessed, a well on the page that what it holds rises out of: a shade deeper than it in dark, and lighter than it and the panes in light. |
paddingDefault 1.25 rem in narrow windows, growing to 1.5 rem from 50 rem wide | 0123456789 | The inset on every side, as a step of the spacing scale, from 1 (0.25 rem) to 9 (4 rem), such as 5 for 1.5 rem; 0 removes it. Without it, the inset follows the window's width. |
radiusDefault 'xl' | 'xl''sm''full''none' | The corner radius: xl, the large 1.75 rem corners of panes; sm, 0.5 rem for small blocks; full, fully rounded ends for a toolbar or a bar of filters; or none, square, for a region that meets the edges of its container. |
skeletonDefault false | boolean | Shows it and its content as a busy skeleton while that loads; turning it on or off renders the content anew. |
render | ReactElement | The element to render the surface as, for its meaning, such as render={<section />}, or another component to render it onto without a wrapper, such as a Column that lays out its content: the surface's class, style and attributes merge into its props. It must forward native props and refs. A div by default. |
ref | Ref< | The rendered element, a div by default. Its type is the element type parameter, which a ref passed in sets: a ref to the element that render makes, such as useRef<HTMLElement>(null) with render={<section />}, type-checks, and `SurfaceProps['ref']` is a ref to the default element, so a wrapper can forward it to one. |
Also accepts the native props of <div>, such as ref, className and aria-* attributes.
placeholders
Stand-in items for data that is loading, so the page renders its normal components over them while a surface around them is a skeleton: `items ?? placeholders<Project>(3)`. Each item has only an `id`, `envui-placeholder-0`, `envui-placeholder-1` and so on, for keys; its other fields are undefined, which the type says, and the components render missing text as bars of a default length for its text style.
placeholders<Item = object>(count: number): Placeholder<Item>[]
isPlaceholder
Whether an item is one of the stand-ins that `placeholders()` returns, by its id, so it holds after the items are serialized, such as from a server component to a client one. It narrows the type: `isPlaceholder(item) ? <Skeleton /> : item.name`, where item.name is the item's own.
isPlaceholder<Item>(item: Item | Placeholder<Item>): item is Placeholder<Item>
useSkeleton
Whether the component is inside a skeleton: a surface with `skeleton` around it. A component of the application's own reads it to give its skeleton a look of its own, such as a chart's.
useSkeleton(): boolean
Part names
Each part's class and state attributes are public and versioned, for an application's CSS to style.
env-surface- A surface: fill, padding and corners.
data-backgrounddefault·muted·page·raised·recesseddata-radiusfull·none·sm·xl
Color properties
Each sets a color of one instance, through style or CSS; its hover, focus and press follow it. They are public and versioned.
--env-surface-container- The surface's fill, which its contents take as the color beneath them.
--env-surface-content- The text.
--env-surface-outline- An edge in this color.
Changelog
- 1.0.0
skeleton, withplaceholders(),isPlaceholder()anduseSkeleton().toneisbackground, with the names of the background roles:paneisdefault,rowmuted,canvaspageandalternateraised;cornersisradius:surfaceisxl,standardsmandpillfull;renderreplacesas. The backgrounds take the semantic background colors.- 1.0.0-prerelease.6
raisedis a step abovedefaultin dark too, withmuted's fill, andrecessedlies belowdefaultin light too, between the page and the panes.- 1.0.0-prerelease.5
background="recessed", a well on the page a shade deeper than it, in--env-color-bg-recessed.