React
The system's components as React components: @arabesquelabs/design-system/react
(dist/react/, from react/src/). They write the same markup the specs
describe, so dist/arabesque.css styles them, and they use the same
helpers (js/) for what they do. The CSS stays the system; React is one
way to write its markup. hunt and any page without React use the classes
and the helpers directly, as before.
See them working, in English and Arabic, light and dark, on the
example pages (in a checkout, npm run serve,
then /examples/). The studio homepage template is built from them:
templates/react/home.tsx.
Use it
React 19 or later. Link the CSS and fonts as for any page (README, "Use it
in a project"), serve dist/icons.svg from the same origin as the page (an
SVG <use> can't reach across origins), then:
import { ArabesqueProvider, Button, Field, Input, SiteHeader, useToast } from "@arabesquelabs/design-system/react";
export function App() {
return (
<ArabesqueProvider lang="en" sprite="/dist/icons.svg">
<SiteHeader links={[{ label: "The idea", href: "#idea" }]} />
<Field label="Full name" hint="As it is on your passport">
<Input autoComplete="name" />
</Field>
<Button variant="primary">Save changes</Button>
</ArabesqueProvider>
);
}
ArabesqueProvider says, once, what every component needs to know about the
page. Without one, the components take the language of <html lang> in the
browser; on the server there's no <html> to read, so a page rendered there
in Arabic needs the provider.
| Setting | What | Default |
|---|---|---|
lang | The page's language: the components' own words (Menu, Clear search, Retry…) and how they write numbers | "en" |
numerals | In Arabic, Western ("latn") or Arabic-Indic ("arab") digits | "latn" |
sprite | The icon sprite's URL | "/dist/icons.svg" |
labels | Your own words for any built-in label | the language's |
For Arabic, set lang="ar" dir="rtl" on <html> as well, and
<ArabesqueProvider lang="ar">: the components' labels, digits, date picker
and construction figure follow it. A part of a page in the other language
takes its own provider and its own lang and dir, as the examples do.
What there is
One module per spec, named after it:
| Module | Components | Spec |
|---|---|---|
button | Button (variant, size, icon, iconEnd, label, busy; an <a> with href), ButtonGroup (label, vertical) | Button |
link, language | TextLink (arrow, external, muted), LanguageLink | Text link, Language link |
field, range | Field, Input (icon, number), Range, Select, Textarea, Affix, AffixText, Fieldset, ErrorMessage, Hint | Field |
choice | Checkbox (indeterminate), Radio, Switch, Choices | Checkbox, radio and switch |
segmented | Segmented (radios), SegmentedButtons (pressed buttons) | Segmented control |
character-count, date-input, date-picker | CharacterCount, DateInput, DatePicker, DateExample | Character count, Date input, Date picker |
forms | ErrorSummary, Search, SummaryList, Confirmation | Error summary, Search, Summary list, Confirmation |
disclosure, card, table, steps, task-list | Disclosure, Card (footer, ribbon), Panel, Stat, Table, Steps, TaskList | Disclosure, Card, Table, Steps, Task list |
badge, tint | Badge, Tag, Highlight, Avatar (size, square), AvatarStack | Badge and tag, Tints |
page-head, nav, site-header, sidebar, footer, breadcrumbs | PageHead, Tabs, SectionNav, SiteHeader (language, sticky, skipTo), ThemeToggle, Shell, Footer, Breadcrumbs, BackLink | Page head, Tabs, Site header, Sidebar, Footer, Breadcrumbs |
notice, phase-banner, toast, dialog, menu, tooltip | Notice (onDismiss; its kind's word as the title by default), SideEffect, PhaseBanner, useToast, Dialog, Menu, useTooltips | Notice, Phase banner, Toast, Dialog, Menu, Tooltip |
empty-state, progress, save-state, bulk-bar, kbd | EmptyState, Spinner (the star; label when nothing beside it says what's happening), Skeleton, Progress, SaveState, RollbackNote, Stale, StaleNote, BulkBar, Kbd, Shortcuts | Empty state, Loading, Pending changes, Bulk bar, Keys |
pagination, stepper, status, rating, popover | Pagination (page, pages, href, onNavigate), pageRange, Stepper (steps, current, href), Status (tone, live, dotOnly), Timeline, List, Rating, RatingValue, Popover (label, icon, title) | Pagination, Stepper, Status, Timeline, List, Rating, Popover |
chart | ChartFigure, ColumnChart, SplitBar, BulletChart | Charts |
brand, pattern, construction, icon | Mark, ArabesqueMark, Star, Wordmark, Lockup (stacked, product, name, mark), Pattern (full, quiet), Hero, HeroCaption, ConstructionFigure, Icon | Brand, Pattern, Construction figure, Icon |
layout | Page, Section (heading, lede), Stack, Cluster, Grid, Split, VisuallyHidden, SkipLink | Layout |
Every prop is typed (dist/react/*.d.ts), with what it's for.
How they work
- Same markup. A component writes what its spec's Anatomy shows, with the same classes and ARIA. If the two ever differ, the spec is right.
- The helpers do the behaviour. Tabs, menus, the site header's menu,
dialogs, the date picker, the character count, tooltips, chart keys and
the pattern are wired by the helpers in
js/, from an effect. They're imported fromjs/where they are (never bundled in), so the date picker and validation still find the sprite at../dist/icons.svg. - Ids are made for you. A field's id, its hint's and its error's are
made with
useIdand joined up (aria-describedby,aria-invalid), so they can't disagree. Give anidwhen something outside needs it: an error summary's link, say. - Server rendering works: nothing touches
documentuntil an effect. The homepage template is rendered on the server, and wired in the page by the helpers alone (see its script). - Focus.
Dialogreturns focus toreturnFocusTowhen it closes, or to what had focus when it opened. PassreturnFocusTo: Safari doesn't focus a button when it's clicked.
Change them
Each component is in react/src/<spec>.tsx. Then:
npm install
npm run build:react # dist/react, the examples, and the homepage template; type-checked
npm test # includes tests/react.test.js
node scripts/check-page.mjs # every example page in Chrome, with axe, light and dark
- A component changes with its CSS and its spec, in the same change.
tests/react.test.jsfails if a CSS component has no React component writing it, if the mark or the icons drift fromassets/andicons/, or if the English and Arabic labels have different keys. - An example is a function in
examples/src/demos.tsx, written in English, with each sentence throught(). Its Arabic comes from the site's Arabic catalogue (showcase-ar.js), orexamples/src/ar.tsfor a new sentence; the build fails on a sentence with no Arabic. Each demo is shown twice on its page, in English and in Arabic, so it mustn't give fixed ids to its elements: let the components make them, or useuseId. - The homepage is
templates/react/home.tsx: its words, in English and Arabic, are incopy. The build writestemplates/home.htmlandtemplates/ar/home.htmlfrom it; don't edit those.
dist/react/, examples/ and the template's HTML are committed, as dist/
is: the site serves the repository as it is. CI rebuilds them and fails if
they differ.