Display primitives
Avatar, Progress, Separator, AspectRatio, ScrollArea,
AccessibleIcon and VisuallyHidden. Each is one element with the right
semantics, and between them they cost almost nothing, because there is almost no
code to ship.
import { Avatar, Progress, Separator, AspectRatio, ScrollArea } from '@apostel/bedrock'
Sourcedisplay.tsx
import { AspectRatio, Avatar, Progress, ScrollArea, Separator } from '../../src/index'
/**
* The primitives that are markup and nothing else. Each renders one element
* with the right semantics — `<progress>`, `<hr>`, an `<img>` with a fallback
* sibling — and between them they cost close to nothing, because there is
* almost no code to ship.
*/
export default function DisplayDemo() {
return (
<div style={{ width: '100%' }}>
<div className="demo-row">
<Avatar.Root>
<Avatar.Image src="/does-not-exist.png" alt="Ada Lovelace" />
<Avatar.Fallback>AL</Avatar.Fallback>
</Avatar.Root>
<span>Fallback, because that image 404s.</span>
</div>
<div className="demo-row">
<Progress.Root value={62} max={100} />
<span>62%</span>
</div>
<div className="demo-row">
<span>Left</span>
<Separator.Root orientation="vertical" style={{ height: '1rem' }} />
<span>Right</span>
</div>
<AspectRatio.Root ratio={16 / 9} style={{ background: 'var(--sunk)', maxWidth: '18rem' }}>
<div style={{ padding: '.5rem' }}>16 / 9</div>
</AspectRatio.Root>
<ScrollArea.Root style={{ height: 90, width: '100%', maxWidth: '18rem', marginTop: '1rem' }}>
<ScrollArea.Viewport>
<div style={{ height: 400, padding: '.5rem' }}>
Native overflow, scrolled by the browser — keyboard, wheel, trackpad momentum and the OS
scrollbar preference all included.
</div>
</ScrollArea.Viewport>
<ScrollArea.Scrollbar />
</ScrollArea.Root>
</div>
)
}Avatar
| part | renders | notes |
|---|---|---|
Root |
<span> |
|
Image |
<img> |
Hides itself on error. |
Fallback |
<span> |
Shown until the image loads, hidden once it does. |
The swap is CSS driven off the image's own load state, not a useState fed by
onLoad. An image that is already in the HTTP cache is therefore never a frame
of flashing initials.
Progress
Renders <progress data-bedrock-progress>.
| prop | type | notes |
|---|---|---|
value |
number |
Omit it entirely for indeterminate. |
max |
number |
Default 1, as the element's own default. |
Progress.Indicator renders nothing, because a <progress> has no children. Style
::-webkit-progress-value and ::-moz-progress-bar.
Indeterminate is the absence of value, which is the element's own rule rather
than a prop bedrock invented.
Separator
Renders <div role="separator">, or nothing accessible at all when
decorative.
| prop | type | notes |
|---|---|---|
orientation |
'horizontal' | 'vertical' |
Written as aria-orientation. |
decorative |
boolean |
Drops the role, so it is not announced. |
A decorative rule between two paragraphs is noise in a screen reader. Marking it so is the difference between a separator and a line.
AspectRatio
Renders one <div> with the CSS aspect-ratio property.
| prop | type | notes |
|---|---|---|
ratio |
number |
e.g. 16 / 9. Default 1. |
Radix uses a padding-bottom wrapper and a ResizeObserver. This is one
property, supported everywhere, in one element.
ScrollArea
| part | renders | notes |
|---|---|---|
Root |
<div> |
|
Viewport |
<div> |
overflow: auto. The browser scrolls it. |
Scrollbar |
<div> |
Styling hook; the scrollbar itself is the UA's. |
Thumb |
nothing | Style the UA scrollbar instead. |
Corner |
nothing | Style the UA scrollbar instead. |
Scrolling is native, so the keyboard, the wheel, trackpad momentum, and the
reader's own "always show scrollbars" preference all work. Style the bar with
scrollbar-width and scrollbar-color, or ::-webkit-scrollbar.
Radix renders custom scrollbars in JavaScript, which is how it can guarantee identical bars everywhere; the cost is momentum, accessibility settings and about 12 kB. This is the trade named plainly in should you switch?.
AccessibleIcon
Wraps a decorative glyph in one element and gives it a name for screen readers,
using VisuallyHidden internally.
<AccessibleIcon.Root label="Delete">
<TrashGlyph />
</AccessibleIcon.Root>
VisuallyHidden
Renders one <span> with the clip-path pattern: invisible on screen, still in
the accessibility tree, and still focusable if it holds a control, which is how
"skip to content" links work.
VISUALLY_HIDDEN is exported as a plain style object if you want the same
treatment on an element bedrock is not rendering.
What is not here
- A loading spinner. Not a primitive; it is a picture.
ScrollAreatype="auto" | "hover" | "always". Those describe Radix's custom scrollbars. The UA's own visibility rules apply instead, and follow the reader's OS setting.