Foundations
What the general @sdxc/ui components are for, the rules every one follows, and every non-color variable they read.
The general catalogue: forms, overlays, navigation, feedback, layout and type, rendered as server HTML. Every namespace builds on it.
Colors come from the roles on Theming and shape from the variables below, so you retune a component by setting a variable.
import "@sdxc/ui/theme.css";
import { … } from "@sdxc/ui";When to reach for it
- Any page, app or marketing: these are the parts every other namespace composes.
- Forms, dialogs, menus, popovers, tabs and the other controls a product needs.
- A component you want to own: sdxc ui add copies one into your project to edit.
Shared ideas
- Ambient headings
Headingtakes its level from the nearestHeadingScope;sizesets the look apart from the level. - Platform firstOverlays use
<dialog>, the Popover API and Invoker Commands; onlyDialogDismissis an island. - Color by role
colortakesbrand,neutral,success,warningordanger; no component hard-codes a hue. - TargetsSmall controls grow an invisible hit area to
--ui-target-size, 44px on a coarse pointer. - Names checkedIcon-only controls and landmarks warn in development without an accessible name.
- Motion
spin,pulseandshimmerare CSS keyframes that soften underprefers-reduced-motion. - Both directionsLogical properties and
:dir(rtl)mirroring keep one markup for both writing directions.
CSS variables
Every custom property the namespace reads or declares, with its default and what it controls.
Reads every role, brand, neutral, success, warning and danger; the Theming page lists them with their light and dark values. The roles are documented on Theming.
Scales
@sdxc/u's theme.css declares spacing, fonts, type and container sizes; radius and shadow are read with these defaults, and declaring one restyles every component.
| Variable | Default | What it controls |
|---|---|---|
--ui-spacing | 0.25rem | Unit of every numeric gap, padding and size step. |
--ui-font-sans | ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif | Body face. |
--ui-font-serif | ui-serif, Georgia, Cambria, "Times New Roman", serif | Serif face. |
--ui-font-mono | ui-monospace, SFMono-Regular, Menlo, Consolas, monospace | Code face. |
--ui-font-display | var(--ui-font-sans) | Face of Heading's display and chapter sizes. |
--ui-text-xs … --ui-text-9xl | 0.75rem, 0.875rem, 1rem, 1.125rem, 1.25rem … 8rem | The type size scale. |
--ui-container-xs … --ui-container-2xl | 20rem, 24rem, 36rem, 48rem, 64rem, 80rem | The container widths components step at. |
--ui-radius-none … --ui-radius-full | 0px, 0.25rem, 0.375rem, 0.5rem, 0.75rem, 9999px (none, sm, md, lg, xl, full) | The corner radius scale. |
--ui-shadow-sm … --ui-shadow-xl | from 0 1px 2px 0 rgb(0 0 0 / 0.05) to 0 20px 25px -5px rgb(0 0 0 / 0.1) | The elevation scale. |
Surfaces
Declared in theme.css, with dark values under .dark and prefers-color-scheme: dark and solid lines under prefers-contrast: more.
| Variable | Default | What it controls |
|---|---|---|
--ui-target-size | 1.5rem; 2.75rem on a coarse pointer | Smallest pointer target a small control grows to. |
--ui-shadow-ring | a 1px ring at 6% black with a soft lift; 8% white in dark | Edge of cards, dialogs and floating surfaces. |
--ui-shadow-ring-hover | the same ring a step stronger | The ring's hover state, for a surface that responds to the pointer. |
--ui-surface-raised | white; a neutral 900–950 mix in dark | Fill of a variant="surface" button. |
--ui-shadow-control | a 1px drop with an inset highlight and ring | Tactile edge of a variant="surface" button. |
--ui-shadow-surface, --ui-shadow-stage | a ring with a small drop; a ring with a deep drop | Edges of raised cards and staged frames, which the landing parts read. |
--ui-image-outline | rgb(0 0 0 / 0.1); rgb(255 255 255 / 0.1) in dark | Inset line that keeps an image's edge visible on a same-tone fill. |
Component tuning
Each falls back to its default in the component; set it on the element, an ancestor or :root.
| Variable | Default | What it controls |
|---|---|---|
--ui-button-radius | var(--ui-radius-md); 9999px on an icon-only button | Corners of Button and LinkButton. |
--ui-button-weight | 500 | Weight of a button's label. |
--ui-button-icon-size-sm, -md, -lg | 2rem, 2.5rem, 3rem | Edge of an icon-only button at each size. |
--ui-popover-offset | 0.5rem | Gap between a popover or hover card and its trigger. |
--ui-overlay-arrow-offset | 0.5rem | How far an OverlayArrow reaches past its surface. |
--ui-surface-padding | 0.25rem | Inner padding of floating surfaces; their inner radius follows it. |
--ui-hover-card-open-delay, --ui-hover-card-close-delay | 0.4s, 0.2s | How long a hover card waits to open and to close. |
--ui-hover-card-z | 50 | Stacking order of a hover card. |
--ui-slider-thumb-size, --ui-slider-thumb-border-width | 1.25rem, 2px | A slider thumb's size and border. |
--ui-slider-track-thickness | 0.5rem | Thickness of a slider's track and fill. |
--ui-switch-track-inline-size, --ui-switch-track-block-size | 2.75rem, 1.5rem | Width and height of a Switch's track. |
--ui-switch-thumb-size, --ui-switch-thumb-inset | 1.25rem, 0.125rem | A Switch thumb's size and its gap to the track's edge. |
--ui-checkbox-size | 1.25rem | Edge of a Checkbox. |
--ui-radio-size, --ui-radio-mark-size | 1.25rem, 0.625rem | A radio's circle and its checked dot. |
--ui-selection-indicator-size | 1rem | Edge of the check mark box in menus and lists. |
--ui-carousel-gap, --ui-carousel-slide-size, --ui-carousel-padding | 1rem, 18rem, 0px | A Carousel's gap, slide size and track padding. |
--ui-spinner-icon-size-sm, -md, -lg | 1rem, 1.25rem, 1.75rem | A Spinner's glyph at each size, also inside a pending Button. |
--ui-image-placeholder-size-sm, -md, -lg | 2rem, 2.5rem, 3rem | An ImagePlaceholder's edge at each size; md is also an Avatar's size. |
--ui-avatar-group-ring | var(--ui-bg, Canvas) | Ring between overlapping avatars in Avatar.Group. |
--ui-item-gap, --ui-item-actions-gap | 0.75rem, 0.5rem | Gaps between an Item's media and content, and between its actions. |
--ui-item-padding-block, --ui-item-padding-inline | 0.625rem, 0.75rem | An Item's padding. |
--ui-item-media-size | 2rem | Edge of an Item's media box. |
--ui-sheet-size | 24rem, at most 90vw | Width of a Sheet. |
--ui-separator-thickness, --ui-separator-min-size | 1px, 1rem | A Separator's thickness and a vertical one's shortest length. |
--ui-meter-track-block-size, --ui-progress-bar-block-size | 0.5rem, 0.5rem | Height of a Meter's and a ProgressBar's track. |
--ui-pagination-control-size | 2.25rem | Edge of each Pagination control. |
--ui-tag-remove-size | 1rem | Edge of a tag's remove button. |
--ui-navigation-menu-viewport-inline-size, -block-size | auto | Size of NavigationMenu's shared viewport, which transitions between panels. |
--ui-typeset-size, --ui-typeset-leading, --ui-typeset-flow | set by Typeset's preset; docs is 1.125rem, 1.75, 1.25em | Body size, line height and space between blocks of rendered prose. |
--ui-aspect-ratio | set by AspectRatio from ratio; 1 | The box's aspect ratio. |
Animations
Each animation from @sdxc/ui/animations reads its options through these, so a variable overrides the option it names.
| Variable | Default | What it controls |
|---|---|---|
--ui-spin-duration, --ui-spin-easing, --ui-spin-fade-duration | 1s, linear, 150ms | One turn of spin(), its easing and its fade in and out. |
--ui-pulse-duration, --ui-pulse-easing, --ui-pulse-fade-duration | 1.6s, ease-in-out, 150ms | One breath of pulse(), its easing and its fade in and out. |
--ui-pulse-min-opacity, --ui-pulse-max-opacity | 0.5, 1 | The dimmest and brightest points of pulse(). |
--ui-shimmer-duration, --ui-shimmer-easing, --ui-shimmer-band-size, --ui-shimmer-fade-duration | 1.6s, ease-in-out, 50%, 150ms | One sweep of shimmer(), its easing, its band's width and its fade. |
--ui-text-shimmer-duration, -easing, -band-size, -angle | 2s, linear, 30%, 90deg | One sweep of textShimmer() through the glyphs, and its band. |
--ui-text-shimmer-color, --ui-text-shimmer-fade-duration | currentColor, 150ms | The band's peak color and the shimmer's fade. |
--ui-scroll-shadow | 0 4px 12px -4px rgb(0 0 0 / 0.18) | Shadow scrollShadow() ramps in under a sticky header. |
Set by the components
Written by a component from its props or by a mixin, and read back by its own parts. Leave them unset.
| Variable | Default | What it controls |
|---|---|---|
--ui-tab-indicator-inline-start, -inline-size, -block-start, -block-size, -opacity | set by Tabs.List from activeIndex and tabSize | Where the active tab's indicator sits and whether it shows. |
--ui-slider-fill | set by Slider.Track from value | How much of the track is filled. |
--ui-drawer-enter-offset, --ui-drawer-exit-offset | set by Drawer from placement | Where a drawer slides in from and out to. |
--ui-sheet-enter-offset, --ui-sheet-exit-offset | set by Sheet from side | Where a sheet slides in from and out to. |
--ui-box-shadow-ring | var(--ui-shadow-ring) | The ring slot of a surface's composite shadow. |
--ui-view-reveal-translate, --ui-scroll-fade-direction | set by viewReveal() and scrollFade() | A reveal's starting offset and a scroll fade's direction, mirrored in RTL. |