# Releases

## 0.2.2 alpha · 2026-11-05

0.2.2 alpha is mostly about the table. A whole row can now be pressed, columns can keep their widths, a long table can hold its headings in view as the page scrolls, and two new looks join the framed one: flat and filled. Popovers can open on hover, from a button they don't draw and to either side, and a tag or a few words in a sentence can open one. Charts get a calmer second set of colors. Nothing a site uses is gone, and What breaks names the two changes a site may have to act on.

### New

- **Tag.** A tag can now be pressed to open something about what it names, such as a small card about a person. Give it `onClick`, or make it a popover's opener, and it becomes a button in the tag's own shape, with hover, pressed and focus looks. A tag that can be removed can't also be pressed.
- **Link.** A piece of text can now open something where it stands, such as a name that opens its card, with `as="button"`. The words keep the color and size of the text around them and break across lines with it, the link's underline says they can be pressed, and a screen reader hears a button. Give them `onClick`, or make them a popover's opener.
- **Tag.** A tag can show a picture of your own before its words, such as an inline SVG, in the icon's place and at the icon's size. Pass it as `leadingContent`.
- **Table.** A row can be marked as the current one, such as the plan in use, in a table with or without checkboxes. It takes the chosen row's fill, and screen readers hear that it is current. Give the row `current: true`, and say it in words in the row too.
- **Table.** A whole row can now be pressed to open something, with `href` for a link or `onClick` for an action. A real link stays a real link, so opening in a new tab works from anywhere on the row. A checkbox, a button or anything else in the row still does only its own job, and the keyboard reaches the row as one stop, with a ring round it that moves no column. Mark the row `current` while what it opened is open, and it keeps the chosen row's fill. A table that doesn't use it stays as it was.
- **Table.** A new flat look for a small table inside a card, with `look="flat"`. It has no frame and no shaded heading row, a thin rule over every row and no room at the sides, so the table's words line up with the card's own. Its rows are one line of text high. A long table with sticking headings, or a wide one with its first column held, keeps the framed look, which stays the default.
- **Table.** A row's details can now open from a button of your own in one of its cells, such as a count that opens the list it counts, with `detailTrigger="cell"`. The table then draws no arrow at the start of the rows and keeps no room for one. Give the table an `id` and keep the open rows in `expanded`; `tableDetailId` gives each details row's id, so your button can say what it opens and whether it is open.
- **Table.** A long table can now keep its heading row in view while the page itself scrolls, with `page-sticky-header`. The table needs no height of its own, so the page keeps one scroll and the mouse wheel always moves the page. The heading row stays under the room the page keeps clear at its top for a fixed bar (its `scroll-padding-top`), and the table's foot stays at the bottom of the window, until the table ends. The table still scrolls sideways, its headings with it, and a sort pressed far down the table leaves the page where it is. Use it in place of a long table in a frame lower than the window.
- **Table.** A column can now be given a width, and the table then keeps all its columns where they are while its rows change, through a filter, pages, a search or a row opening. Give a column `width`: a share of the table, a size token, or `rest` for the room the others leave. Long text wraps inside its column. On a narrow screen the table stops at a least width and scrolls sideways; choose it with `minWidth`. A table that gives no column a width doesn't change.
- **Table.** A new filled look for a calmer table on the page, with `look="filled"`. The heading row and the foot sit on a soft fill with no lines between the headings, group rows are sunken and low, and a column that is not sorted shows its arrow only under the pointer or the keyboard. The foot grows with what it holds, and the look works with every other table option, including long tables and a pinned first column.
- **Table.** A column can now be headed by a block taller than one line, such as a name, a line of facts and its own buttons, with `tallHeader`. The heading row grows to the tallest heading, and the other headings keep their one line. A block can hold buttons, so in such a heading the arrow alone sorts. In a long table, whatever gets focus lands clear of the heading, and a heading that would take more than half of what shows scrolls away with the rows.
- **Table.** One table can now sit tighter than the page around it, with `density="compact"`. Its rows, heading row and foot step down together, with the pagination and tags in them, and nothing else on the page changes. In plain HTML, set `data-density="compact"` on the table's frame.
- **Table.** Every cell can now start at the top of its row instead of in its middle, with `align-top`, for cells of very different heights. Each cell's first line stands level with the others, so a figure stays beside the name it belongs to, in a phone's held first column too. A row of one line looks the same either way.
- **Popover.** A popover can now also open while the pointer rests on its opener, for a card that previews what a name or a tag points at, with `openOnHover`. It waits as long as a tooltip does, stays while the pointer moves into it and closes a moment after the pointer has left both. It leaves keyboard focus where it is. A press, the keyboard and touch open it as before, and without the switch nothing changes.
- **Popover.** A popover can now open from a button it does not draw, such as a table row's own, with `openerId`. The panel hangs on that button and gives focus back to it, and a press on the button closes what it opened. Use `hangOnId` to hang the panel on something else, such as the name in a row.
- **Table.** A press on a row can now open a popover with no button of your own, so the row stays one Tab stop. Give the popover the row's button with `tableRowPressId`, and Escape puts focus back on the row, a press on a held first column included.
- **Popover.** A popover can now open to the left or right of its opener as well as below or above it, with `side="left"` or `side="right"`. Without room on either side, as on a phone, it opens below.
- **Popover.** A popover can now point at what opened it, with `pointer`: a small triangle on the edge facing the opener, on whichever side it opened. Without the switch nothing changes.
- **Cockpit chart colors.** A second set of data colors, calmer and less bright, for dashboards and tools people read for long stretches. Set `data-palette="cockpit"` on `<html>` and every chart color changes, in light and dark. Without it, nothing changes.
- **Status colors for chart marks.** Good, warning and bad, for a mark that shows a real state, such as a bar over its limit. They are calmer than the alert colors, which stay for badges, banners, icons and text, and they never match a series color.

### Changed

- **Section heading.** The gap between the title and the line under it is now 8, one step smaller than the 16 it was, as the design system's Figma component now draws it. Every page that uses a section heading, and anything that holds one such as a collapsible section, gets a little tighter between the two. The space between the heading and its action in a narrow space stays as it was.
- **Link.** The underline sits further below the words and is much quieter at rest, in both themes, so it no longer reads nearly as strong as the words. It grows stronger under the pointer and strongest while pressed. Your own links can draw the same line with the design tokens `--smbk-color-text-link-underline`, its new `-pressed` partner, `--smbk-border-width-link-underline` and `--smbk-space-link-underline`.
- **Link.** An icon in a link is no longer underlined, in any browser, at rest, under the pointer or pressed. The line runs under the words only, not under the icon or the gap before it, and the icon still stays on the same line as the word beside it. When you write a link with an icon by hand, keep its words in the label part, which now draws the underline.
- **Table.** In a long table with its own lower frame (`sticky-header`), the foot now stays at the bottom of the frame while the rows scroll under it, as the heading row stays at its top. A row's control that gets focus no longer lands under either of them.
- **Table.** An open row no longer draws a line between itself and its details, so the two read as one. The details row keeps the line under it.
- **Reduced motion in the rules every project keeps.** They now say what the components already do: when a reader asks for reduced motion, there is less motion, not none. Anything that slides, rises, grows or turns lands at once, and fades still play. The motion design tokens' description says the same.
- **Pagination.** Large numbers are now written the way the page's language writes them, so 1,116 and 11,151-11,157 in English. That holds for the page numbers and their names, the counts and the range's choices. Name another language with `locale`. Words you give yourself, such as `countText`, still receive the bare numbers.
- **Pagination.** The range type's select is now the small one unless you ask for another with `selectSize`, since the range type sits in a table's foot.
- **Drawings and extra colors in the rules every project keeps.** Before reporting that a component differs from a drawing, a project now checks that the drawing uses the component: a part drawn by hand is the project's own variation. A color a project has beyond the system's stays in a palette of its own, and is not asked for as a token.
- **Checker.** A new rule, removed-prop, finds a prop that a Release took off a component, such as `aria-keyshortcuts` on `ToolbarTool` and `SegmentedControl`, and names what to use instead. Nothing warned of these before: TypeScript doesn't check a hyphenated name in JSX, and a name the element also knows goes through to the element.
- **Segmented control.** Its page now says a bar may have nothing chosen, when what the page shows is none of the choices, such as days picked on a calendar. Give `value` an empty string, and say near the bar what is showing. The bar always drew this correctly, and it doesn't change.

### Fixed

- **Pagination.** A page number of three digits or more now fits its button. A button stays a square up to two digits and grows with a longer number, and a page turning current moves nothing beside it.
- **Donut chart.** A long figure in the middle no longer runs into the ring. It steps down in size by itself, so `$99,999` and `$1,250,000` keep clear, and a figure that already fit stays as it was. The middle holds ten characters; give a longer total a shorter form with `figure`. In plain HTML, add `smbk-donut-chart__figure--size-md` or `--size-sm` yourself.
- **Date and time picker.** Its page no longer tells you not to use it for a range of dates, which it does with `type="date-range"`.
- **Popover, dropdown, select and navigation menu.** In Safari, pressing the opener of an open panel could close it and open it again at once, so the panel stayed open. It happened when a part around the opener could take focus, such as a `main` with `tabindex="-1"` for a skip link, or a table's scrolling frame. The press now closes it, as in other browsers. In Firefox, pressing the words inside an open navigation panel no longer closes it.
- **Breadcrumbs.** On hover, the line under a crumb now runs under its name only, not under its icon or the gap beside it. The name has a new `label` part.
- **Popover, dropdown and tooltip.** A panel left open when a part of the page around its opener goes full screen no longer ends up hidden behind that part. It stays shown and moves with its opener.
- **Navigation menu.** In a narrow space, a press elsewhere in the moment just after a panel opened could close it. The panel now stays open from the start, as it does later.
- **Table.** A chosen or current row now keeps its fill while the pointer rests on it. A row pressed with a mouse used to show the hover fill until the pointer left, so it did not look current straight after the press.
- **Scrollbar.** In Chrome, a page could stop scrolling for a whole swipe when the pointer was over a table or another part with its own scrollbar. It happened even when the part had nothing to scroll. The bar no longer lays a clear box over the part's content, so the page keeps moving.
- **Scrollbar.** A table's frame, or any other part with the system's scrollbar, now gives its true width the moment it gets narrower. Before, a page that measured it right then got the old, wider width, and a layout deciding what fits beside it could choose wrong. While the bar is hidden, it now takes no part in the page's layout.
- **Table.** In a long table with its own lower frame (`sticky-header`), pressing a heading to sort no longer throws the rows in the frame away from where the reader was. The browser used to follow a row the sort moved.
- **Table.** In a long table, nothing shows through the heading row any more as the rows pass under it. Words and lines used to show along its top edge and between two headings, and the line under it stopped short at every column. It now runs unbroken from one side of the table to the other, in the framed and filled looks.
- **Table.** In a long table that follows the page, the foot's top line now stays one clean line as the rows pass behind it. On a standard screen it used to blur across two pixels, with the rows showing through and the foot's words gone soft, wherever the table landed between two pixels.
- **Table.** In a long table that follows the page, the line under the heading row now stays one clean line as the rows pass behind it. On a standard screen it used to blur across two pixels, with the rows showing through, wherever the table landed between two pixels.
- **Segmented control.** A choice that shows a count, such as "Short 8", no longer changes width when the count changes. Every digit now takes the same room, so the bar and anything after it on the line stay still.

### What breaks

- **Page bounce.** A page built on the system no longer bounces past its top or bottom, on a phone or a Mac. In Chrome on Android, pulling down no longer reloads the page either. A project that wants both back sets `overscroll-behavior-y: auto` on its `<html>`.
- **Checker.** A project that still gives one of these removed props to a component now fails its check: `aria-keyshortcuts` on `ToolbarTool` and `SegmentedControl` (use `shortcut`), `scheme` on `Avatar` and `variant` on `Checkbox` (use `tone`), `underline` on `Link` (every link is underlined; set `standalone` on one that stands on its own), `media` on `Card` (use `layout`), and `onClose` on `Modal`, `Drawer` and `CommandPalette` (use `onOpenChange`).

### Known gaps

- **Table rows can't be reordered.** The table has no drag handle in this Release, so a site that needs to move rows builds that itself for now.
- **Five components are still Proposed.** The alert dialog, collapsible, one-time code input, navigation menu and menubar stay marked Proposed, so their look and props may still change in a later Release.
- **A sideways scrollbar can cover a short part's content.** While the bar shows, its track takes presses along a thin strip at the part's lower edge. On a line of small chips that strip is the lower half of each chip, so a press there grabs the bar instead of the chip.
- **Some color pairs fall short of contrast.** A few colors measure below the contrast ratio WCAG asks for against the background they sit on. Text needs 4.5 to 1; the edge or mark that shows a control or its state needs 3 to 1. Some pairs are still to be fixed. Others are kept on purpose, a choice of taste for the system's look. The Contrast section of the [color page](https://design.simbolik.ai/foundations/color/#contrast) lists every pair, what it measures and what it needs.

### Take it

The code is on GitHub, https://github.com/simbolik-lab/simbolik-design-system, tagged `v0.2.2-alpha`. On that Release, download `simbolik-0.2.2-alpha.zip`. It holds one `design-system/` folder with what a site builds with and every license, ready to use with no build. The README on GitHub says how to use each part.

A site on 0.2.1 alpha swaps its copy of the bundle for this one, then reads What breaks. The conformance checker names each class, custom property and removed React prop the site still uses. A site on 0.2 alpha reads the [0.2.1 alpha notes](https://design.simbolik.ai/releases/0.2.1-alpha/) first, and a site on 0.1.2 alpha or earlier reads the [0.2 alpha notes](https://design.simbolik.ai/releases/0.2.0-alpha/) before those.

The Figma file the design is drawn in is on Figma Community, https://www.figma.com/community/file/1688324308358870630, where anyone can open it and copy it.

The code is under the MIT License and the Figma file under CC BY 4.0. The [Licenses page](https://design.simbolik.ai/licenses/) says what each one asks.

## 0.2.1 alpha · 2026-10-30

0.2.1 alpha adds five components: an alert dialog, a collapsible, a one-time code input, a navigation menu and a menubar. The checkbox, radio, accordion and sidebar now move as they change. Every part that scrolls inside itself draws a thin scrollbar that takes no room. The rest is fixes and small additions found while building real pages with the system. Two small things break, and What breaks says what to use instead.

### New

- **Combobox active option.** `onActiveChange` tells the page which option is active, the one Enter would pick, and what made it active: the arrow keys, the pointer, or a mouse at rest that the list opened under. Closing the list or typing tells it nothing is. A page can show the option in a preview before it's picked.
- **Pagination as links.** Give each page's address with `href`, and every page, Previous and Next become links. They work with no script, for sites built ahead of time and pages a search engine should follow. The current page keeps its look.
- **Selectable list without its tick.** `tickless` draws a selectable list's chosen row by its fill and a bolder title alone, with no tick. It's for rows that open as they're chosen, such as an inbox beside its reading pane, where a tick would read as kept for later. The keyboard and what a screen reader hears stay the same. In plain HTML it's `smbk-list--tickless`.
- **List rows that open a new tab.** A link row takes `target` and `rel`, so a row that leads to another site can open in a new tab. Its name then ends with "(opens in a new tab)" for screen readers. In plain HTML, end the row's title with a `smbk-visually-hidden` span holding those words.
- **Synonym list.** `synonym-list.json` says which common design-system name each Simbolik name means, such as `brand` for `primary`. It also says which token files hold raw values and which hold roles, and lists the four modes and their values.
- **Theme wipe.** A new `applyTheme()`, beside the theme switch, sets the page's theme with a wipe. The new theme grows over the whole page in a circle from the option pressed, in one second. Call it from the switch's `onChange`, which now also passes the option pressed. Readers who ask for reduced motion, and browsers without view transitions, get the change at once, as before. The timing is 2 new motion design tokens, `--smbk-motion-theme-wipe-duration` and `--smbk-motion-theme-wipe-easing`.
- **Alert dialog.** A new component that asks before something that can't be undone, such as deleting a project. It looks like the modal, with its icon in red when the confirm action is a danger one. Focus starts on Cancel, and a click beside it doesn't close it, so the reader has to choose. Escape and Cancel close it; the confirm action calls `onConfirm` and closes it.
- **Button width and content.** A button takes `full-width` to stretch across its space, its label still centered. It also takes `leadingContent`, such as a small avatar before the label, and `count`, a number after the label in the badge's small pill. In plain HTML they're `smbk-btn--full-width`, `smbk-btn__leading-content` and a badge with `smbk-btn__count`.
- **Large input.** The input takes `size="lg"`, 48 tall, to stand beside large buttons. It keeps the medium text and icons. In plain HTML it's `smbk-input--size-lg`.
- **Date range.** The date picker takes `type="date-range"`, with 2 date fields for a first and a last day, typed or picked on the range calendar. Its value is one string, the 2 days as `YYYY-MM-DD/YYYY-MM-DD`, and a form gets both days under one name. On a phone the fields stack.
- **Toast shortcut.** F6 moves focus to the newest toast, and F6 again goes back. A toast with an action no longer takes a trip through the whole page to reach.
- **Stat trend and chart.** A stat takes `trend`, a mark of the change after its figure, such as a small badge with "+12%". It also takes `chart`, a small chart under its line, such as a sparkline. In plain HTML they're `smbk-stat__trend` inside the figure and `smbk-stat__chart` after the line.
- **Select groups and rich choices.** A select's choices can sit in groups, each under a small heading, with a line between groups. Screen readers say which group a choice is in. A choice can also show a picture or an icon before its label, and a second line under it, such as a person's role. In plain HTML a group is `smbk-select__group`. A rich choice is `smbk-select__option--rich`, with `smbk-select__option-lead`, `smbk-select__option-text` and `smbk-select__option-description`.
- **Collapsible.** A new component, one row that shows or hides the content under it, for detail most readers can skip, such as older releases. It opens and closes with the accordion's motion. Its block is `smbk-collapsible`.
- **One-time code input.** A new component for a code sent by email or text message, in 6 boxes, 2 groups of 3. They act as one field, so pasting a code, the phone's suggested code and screen readers all treat it as one value. It takes a field's label, help and error. Its block is `smbk-one-time-code-input`.
- **Navigation menu.** A new component for a site header's links. An item with a caret opens a wide panel of links, each with a line of description, and a featured column. On a phone the list stacks and a panel opens in place under its item. Its block is `smbk-navigation-menu`.
- **Menubar.** A new component, a row of menus as at the top of a desktop app (File, Edit, View). The arrow keys move along the bar and from one open menu to the next, and the pointer does the same. Its menus are the dropdown's, with second menus and single choices. Its block is `smbk-menubar`.
- **Dropdown submenus and single choice.** An item can open a second menu beside it, by the pointer, the right arrow or Enter. The left arrow or Escape closes it again. A group of items can be a single choice, the chosen one marked with a tick after its label. In plain HTML, `smbk-dropdown__submenu` holds the item and its second menu.
- **Right-click menu.** A dropdown given an `area` opens where the pointer is, on a right click on that area. A finger held on it does the same on a touch screen, as do Shift+F10 and the menu key from the keyboard. Focus goes back where it was when the menu closes. The hold is a new motion design token, `--smbk-motion-hold-delay`.
- **Page header without a main action.** `mainAction={false}` draws every action as an outline button, for a page whose main action sits somewhere else, such as the app's toolbar. In plain HTML, mark each action `smbk-page-header__action--secondary`. An action can also be the system's own button or button with a note, given as its `button`. The header still folds it behind More actions on a phone.
- **Narrow sidebar.** `width="sm"` makes a sidebar's open panel 240 wide, for a dense app's list of pages. The column of icons keeps its width. In plain HTML it's `smbk-sidebar--width-sm`.
- **Medium sidebar children.** `child="md"` draws a sidebar's children as tall as their parent, 40 with 16 px text. It's for children a reader opens as often as the item above them. Their labels and the tree line stay where they were. Without it they stay a step smaller, as before, and a small sidebar keeps every row small. The navigation alone, `SidebarNav`, takes it too. In plain HTML it's `smbk-sidebar--child-md`.
- **Keys in tooltips.** A toolbar tool, a segmented control and the tooltip take a `shortcut`. The tooltip shows the key after the name as a small key cap, and the control gives it to screen readers as `aria-keyshortcuts`. The page still listens for the key itself. In plain HTML the key cap is `smbk-tooltip__key`.
- **Small empty state.** An empty state takes `size="sm"` for one panel among many, such as on a dashboard. Its title is a label, and its icon and gaps are smaller, so an empty panel no longer reads louder than its neighbors. In plain HTML it's `smbk-empty-state--size-sm`.
- **Small description list.** A description list takes `size="sm"` for a narrow panel, such as a settings column about 320 to 360 wide. It uses the small text sizes and closer rows. Side by side, the names take about a quarter of the row, so short values stay on one line. It keeps its columns on a phone. In plain HTML it's `smbk-description-list--size-sm`.
- **Field group help with blocks.** A field group's `description` can hold paragraphs, a list and code, and screen readers still read all of it as the group's description. The field message takes `as="div"` for this. In plain HTML, write the help as a `div` with the field message's classes, its words in a `div` with `smbk-field-message__text`.
- **Combobox swatches, badges and groups.** A combobox option can show an `icon` or a color `swatch` before its label. After it, it can show quieter `detail` words or a `badge`, such as a color's contrast. Screen readers read those words with the label. Options can sit in groups under a heading, and typing hides a group with nothing that matches. With one choice, the box shows the chosen swatch or icon before its label. The new parts are `smbk-combobox__option-lead`, `smbk-combobox__option-detail` and `smbk-combobox__option-badge`.
- **Bar chart colors and focus.** A stacked series can keep its own color whichever series are shown, with `swatch` (1 to 8). `legendEmpty={false}` leaves series with nothing in them out of the legend. With `focusable`, each bar takes focus and says its figures, as one Tab stop moved with the arrow keys. `onActiveChange` tells the page which bar is pointed at or focused, for a readout under the chart.
- **Donut chart colors and focus.** A part can keep its own color with `swatch`, and `legendEmpty={false}` leaves parts of zero out of the legend. With `focusable`, each part takes focus and says its name, value and share, and `onActiveChange` tells the page which part is pointed at or focused.
- **Table rows left out of choosing.** In a selectable table, a row given `selectable: false` shows no checkbox but keeps its room, so the column lines up. The checkbox in the heading counts only the rows that can be chosen. A row also passes any `data-` attribute it's given to its row element. In plain HTML the kept room is `smbk-table__choose-space`.
- **Board groups that fold.** A board group's label can be a heading in the page's outline, with `headingLevel`. A group can fold under its label, always or only on a phone (`fold="always"` or `fold="narrow"`), and starts closed unless `defaultExpanded` is set. In plain HTML it's a `details` element with `smbk-board-column__group--fold-always` or `smbk-board-column__group--fold-narrow`.
- **Timeline events that unfold.** An event can hold more text, given as `more`, that unfolds under it in place when it's pressed. Its row tells screen readers whether it's open. In plain HTML the event's body holds a `details` element with `smbk-timeline__disclosure`.
- **Contained slider.** The slider takes `look="contained"`, a filled bar as tall as a button with its label and value inside. Where the red passes under the words, they turn white, so they read on both parts. A long label wraps and the bar grows to hold it. In plain HTML it's `smbk-slider--look-contained`, with the label row inside the rail and a white copy of it inside the fill.

### Changed

- **Compact tools.** The rules every project keeps now let a tool set the compact density on `<html>`: a screen its own people use at a desk to make or manage something. A site's readers still get the comfortable density. The checker never asked for one or the other, so nothing changes there.
- **Tooltip wait.** A tooltip now waits a second while the mouse rests on its control. A pointer passing over a toolbar no longer pops up a row of bubbles. A label's info icon waits about a third of a second, since pointing at it is asking for help. Keyboard focus still shows both at once. The waits are 2 new motion design tokens, `--smbk-motion-tooltip-open-delay` and `--smbk-motion-help-open-delay`.
- **Stat in a card.** A stat in a card's slot drops its own padding and surface, so its name lines up with the card's header. The card gets shorter too.
- **Badge and tag edges.** A soft badge and a tag in a feedback tone now draw a pale edge in their tone, so a row of them reads quieter. Info and warning get the pale edge colors success and danger already had, 2 design tokens: `--smbk-color-feedback-info-border-subtle` and `--smbk-color-feedback-warning-border-subtle`.
- **Popover focus.** Opening a popover now moves focus into it: to its first field, or to the panel itself, named by its title. Screen readers announce it as it opens. Before, focus stayed on the button.
- **Menu keys.** In a dropdown menu, typing a letter jumps to the item that starts with it. Disabled items can be reached with the arrows and are read as unavailable; pressing one does nothing. A click opens the menu with focus on the menu itself, not its first item. Enter and Space still open it on the first item.
- **Toast announcements.** A danger toast is announced at once, interrupting. The others are announced politely, as before. The toast region is now a named landmark, with 2 hidden announcers beside it that read each toast. A page's own tests that looked for the region as a status now look for a region.
- **Error look from aria-invalid.** A field, checkbox, radio, choice card or file upload marked `aria-invalid="true"` now draws the error look, with or without the error class. Plain HTML that marks its errors for screen readers gets the red edge too; add the warning icon in the markup.
- **Accordion.** A disabled item now stays in the Tab order and is read as unavailable. It still doesn't open.
- **Accordion motion.** An item now unfolds and folds back the same way, on a soft curve. Its content fades in from a slight blur, the foot of the text fades as it moves, and the caret turns in step. A second press halfway turns it round, and it moves the same in every browser. With reduced motion, an item opens at once and its content fades in; closing, the content fades out first. The timing is 3 new motion design tokens, `--smbk-motion-expand-duration`, `--smbk-motion-expand-easing` and `--smbk-motion-expand-blur`. They use a new curve, `--smbk-easing-cubic-out`. In plain HTML, Chrome and Edge move it the same way, without the fading foot. Other browsers still open it at once.
- **Checkbox motion.** Ticking a box now fills it from a little smaller as the fill fades in. Then the tick draws itself from its start to its tip. Unticking erases the tick at once while the fill shrinks away, and a mixed box draws its dash without the wait. A box ticked as the page loads simply shows it. With reduced motion, the fill and the tick only fade. The fill is drawn on the box's own `::before`. The timing is 5 new motion design tokens, `--smbk-motion-fill-duration`, `--smbk-motion-fill-easing`, `--smbk-motion-draw-duration`, `--smbk-motion-draw-delay` and `--smbk-motion-draw-easing`.
- **Radio motion.** Choosing a radio fills its circle the same way. Its dot pops in, growing a little past its size and settling back, while the dot it replaces shrinks away. The circle gives a little while it's pressed. With reduced motion, the fill and the dot only fade. The timing is 2 new motion design tokens, `--smbk-motion-pop-duration` and `--smbk-motion-pop-easing`. The curve, `--smbk-easing-back-out`, is the first in the system that runs past its end.
- **Sidebar motion.** The sidebar now folds and unfolds on a curve that is slow to leave and slow to land. Pressed on the way, it turns round where it is. Closing, the words fade into a slight blur before the rows narrow. Opening, they come back as the rows reach full width. Group labels and open groups fold with it in every browser, and the rows below follow smoothly. Going from kept open to kept closed now moves the same way. In the auto column, the icons below an open group no longer sit lower than the rest. A group's children now unfold like an accordion item, the same in every browser. With reduced motion, the sidebar changes at once and the words still fade in. The timing is 5 new motion design tokens, each starting with `--smbk-motion-fold-`: `duration`, `easing`, `label-duration`, `label-easing` and `blur`.
- **Scrollbars.** Parts that scroll inside themselves now draw the system's own scrollbar, over their content at the edge. That covers menus, the select's and combobox's lists, popovers, the modal's and drawer's bodies, the command palette, the sidebar, logs, code, tables, boards, the tabs' row and the text area. The bar takes no room. So where a computer always shows scrollbars, a list no longer grows wider and a code block no longer grows taller. It shows while the mouse is over the part or the part scrolls, and fades half a second after the last scroll. Its thumb is thin and see-through and widens under the mouse. Drag it, or press its track to jump there. A touch screen keeps the browser's own bar. The thin hint under a wide table or board fades while the bar shows. Markup written by hand keeps the browser's thin bar too. The `data-scrollbar` mark and the `smbk-scrollbar` part come from the script. The wait is a new motion design token, `--smbk-motion-scrollbar-hide-delay`.
- **Showroom home page.** Every component now drifts past on a wall of their card pictures, seen from above at an angle, in place of the 14 working examples. Point at one, or reach it with Tab and the arrow keys, to lift it and see its name; it opens its page. Behind the title, a faint field of characters breathes from edge to edge. Both stand still with reduced motion.
- **Select keys.** Home and End open a closed select on its first or last choice.
- **Server components.** Every component file that uses state or events starts with `'use client'`, so a Next.js App Router page can import it. Files that only draw markup, like the button, stay usable on the server.
- **Popover and dropdown wrapper.** The element around the button and its panel is now a `div`, which HTML allows to hold the panel. Its class and its look are the same.
- **Sunken wells.** Fields, checkboxes, slider bands, logs, table headers and other sunken parts were the page's own gray. Now they draw a see-through shade. They sit a step below whatever is under them, the page included. A field on the page no longer shows by its edge alone. On a card they look about as before. `--smbk-color-surface-sunken` is now see-through, so a part that draws it over a picture or a colored fill lets that show through.

### Fixed

- **Hidden parts.** Any part of the design system given the `hidden` attribute is now hidden, such as a tag, an empty state or a list row that a page's own script filters out. Before, a part's own display outweighed the attribute, so it stayed on screen. Panels still fade out as they close, and `hidden="until-found"` still works.
- **Tooltip on a select.** A tooltip given a select as its target now shows at once when the select takes keyboard focus, and hides when focus leaves, as it does on a button. Before, it showed only on pointing. Pointing still waits a second.
- **Toggle chip pressed by a script.** A toggle chip now shows its tick whenever it's on, including when a page's own script presses it by setting `aria-pressed="true"`. Before, only a chip React rendered as selected showed the tick, so a chip pressed by a script showed it was on by color alone. Every toggle chip now carries its tick in the markup, hidden while it is off.
- **Bars beside a held first column.** Bars and meters in the columns that scroll sideways now pass under the held first column. Before, they drew over the names in it as they scrolled past.
- **Popover in a table heading.** A table heading's info popover now wraps its words onto as many lines as they need. Before, it took the heading's single line, so a long explanation ran past the panel and had to be scrolled sideways. Any popover opened from a place that keeps its words on one line, such as a bar, wraps the same way.
- **Pinned rows in Firefox.** In a table that keeps its first column in view, a pinned row no longer draws a thin red line along its foot in Firefox. Its red edge on the start side is unchanged.
- **Required date picker.** A required date picker, or date range, left empty now stops the form from sending, as a required select does. Its first empty field takes focus, and it shows its error look until it holds a value. A disabled or read-only picker never stops the form.
- **Lines through a held first column.** In a table that keeps its first column in view (`pin-first`), the lines between rows and under the headings now run straight through that column. Before, the column drew its own copy a pixel off the table's, so its lines looked heavier and stepped at its edge.
- **Backup fonts.** Light, medium, semibold and bold text now each have a stand-in face of their own width, in `assets/fonts/fallback.css` and `assets/fonts/fonts.css`. A line drawn before its font arrives breaks at about the same word as after, so the page barely moves when the font comes in. Before, one stand-in sized to the regular weight set light text a line longer and bold text a line shorter. Geist and Funnel Display's regular stand-ins are a little narrower too, measured as browsers set the text.
- **Sidebar touch.** On a touch screen, the first and last items in a sidebar group now take a press halfway into the gap beside them. The other rows already did. Before, their press area stopped at their own edge.
- **Sparkline entrance in Chrome.** A sparkline below the fold now draws when it's scrolled into view in Chrome, Edge and other Chromium browsers. It used to stay empty. The line and its dot now sit in a new `smbk-sparkline__plot` part. Markup written by hand can leave it out and still shows the sparkline, just without the reveal.
- **Forms.** A required select, combobox or number field left empty now stops the form from sending. The browser focuses it, and it shows its error look until it's filled. The select also writes its value to a hidden native select, so the browser's autofill can fill it. A disabled number field no longer sends its value. A form's Reset button now puts the select, combobox, date picker, slider, color picker, radio group and selectable list back where they started.
- **A page's own handlers.** A page's own `onClick` or `onCancel` on a modal or drawer no longer switches off closing on Escape and on the scrim. Both run now. The same goes for a page's key handler on a date picker, and its click and focus handlers on a selectable list's rows. A popover or dropdown keeps its own open state over a `hidden` the page passes.
- **Tabs in right-to-left pages.** The arrow keys follow the reading direction, so in Arabic or Hebrew the left arrow moves to the next tab.
- **Select placement.** A select or combobox given a `boundary` now places its list inside it the first time it opens.
- **Font files.** The icon font's stylesheet and the font stylesheets in `assets/` now name only each font's WOFF2 file, the one every browser takes. A site's build tool no longer copies about 3.4 MB of WOFF, TTF and SVG files into what it uploads.
- **Checker and touch areas.** The checker no longer flags a touch screen's press area that stops halfway into the gap beside it. That's half the gap's space token made negative, such as `var(--smbk-space-inline-sm) / -2`. That form passes only on the `inset` of a `::before` or `::after` inside `@media (pointer: coarse)`. Anywhere else it's still a new value made from a token.

### What breaks

- **Dropdown sizes.** The dropdown's `default` and `small` sizes are gone, as props and as the classes `smbk-dropdown--size-default` and `smbk-dropdown--size-small`. Use `md` and `sm`, as on the other controls, and the classes `smbk-dropdown--size-md` and `smbk-dropdown--size-sm`. They're also on the list of a select, a combobox or a sidebar flyout written in plain HTML.
- **Keys on the segmented control and toolbar tool.** `SegmentedControl` and `ToolbarTool` no longer pass an `aria-keyshortcuts` prop through. Give the key as `shortcut`. Screen readers are told it the same way, and the tooltip shows it as a key cap.

### Hotfix 1 · 2026-10-30

- **Sidebar flyout.** In a kept-closed sidebar, the menu that opens from an item with children shows above the page again. Since this Release's scrollbars, a part of the page beside the sidebar on a layer of its own, such as a card, a chart or a sticky bar, drew over it. The menu now opens in the browser's top layer, as the dropdown's menus do.

### Known gaps

- **Table rows can't be reordered.** The table has no drag handle in this Release, so a site that needs to move rows builds that itself for now.
- **Five components are new and Proposed.** The alert dialog, collapsible, one-time code input, navigation menu and menubar are marked Proposed. Their look and props may still change in a later Release.
- **Some color pairs fall short of contrast.** A few colors measure below the contrast ratio WCAG asks for against the background they sit on. Text needs 4.5 to 1; the edge or mark that shows a control or its state needs 3 to 1. Some pairs are still to be fixed. Others are kept on purpose, a choice of taste for the system's look. The Contrast section of the [color page](https://design.simbolik.ai/foundations/color/#contrast) lists every pair, what it measures and what it needs.

### Take it

The code is on GitHub, https://github.com/simbolik-lab/simbolik-design-system, tagged `v0.2.1-alpha`. On that Release, download `simbolik-0.2.1-alpha.zip`. It holds one `design-system/` folder with what a site builds with and every license, ready to use with no build. The README on GitHub says how to use each part.

A site on 0.2 alpha swaps its copy of the bundle for this one, then moves off every name What breaks lists. The conformance checker names each class and custom property the site still uses that is gone; React props it can't see, so search the site's code for the props listed there. A site still on 0.1.2 alpha or earlier reads the [0.2 alpha notes](https://design.simbolik.ai/releases/0.2.0-alpha/) first.

The Figma file the design is drawn in is on Figma Community, https://www.figma.com/community/file/1688324308358870630, where anyone can open it and copy it.

The code is under the MIT License and the Figma file under CC BY 4.0. The [Licenses page](https://design.simbolik.ai/licenses/) says what each one asks.

## 0.2 alpha · 2026-10-20

0.2 alpha brings the code in line with the second version of the Figma design: new color ramps, layout tokens that switch between phone and desktop, and components drawn again to match. It renames once, too, and drops the design tokens Figma retired. Every old name from 0.1.2 alpha is gone, and What breaks lists each one with what to use instead. Each GitHub Release now has the whole bundle as a download, and the README opens with a quick start. The Showroom's Docs are 8 short pages.

### New

- **Layout tokens.** A page's sections get their own tokens. They cover section padding, the gap under a heading, the gaps between blocks, a grid's gap and columns, and container widths. They also cover the width of a column of text, the least width of a column, the header's height and a section's corners. Each has a phone value and a desktop value, and they switch at the same width as the components' wide form. Put `data-layout="narrow"` or `data-layout="wide"` on an element to force either inside it.
- **Text spacing tokens.** The gaps between texts have names. There's one from paragraph to paragraph, from a heading to its text, from a title to the caption under it, from one list item to the next, and between sections of text. Each is set for text at its full line height.
- **Colors.** New roles include `surface/selected`, a see-through fill for the current or chosen item that shows on any background. There's also a switch thumb that stays white in both themes, with a color for its icon. `surface/scrim` is a dark band, the same in both themes, that keeps light text readable over a picture. Every disabled action now shares one set of colors, and there are new colors for focus on brand surfaces and for charts.
- **Text styles.** The display and heading styles each have a light version. Body MD Medium and Body SM Medium are new, and so is a 14 px field style for dense desktop screens. Two code styles set code and keys in Geist Mono. Heading 2XS has a bold version too, for the titles of modals and drawers.
- **Backup fonts.** Each font family now names backups after it: a stand-in face, then the system's own font. The stand-in face is a font already on the reader's device, scaled and spaced to match the family, so a page drawn before its fonts arrive keeps its layout and barely moves when they do. Text no longer shows in a serif first. `assets/fonts/fonts.css` holds the stand-in faces, and `assets/fonts/fallback.css` holds them alone, for a site that builds its own font sheet.
- **Release files for programs.** From the next Release on, a file beside each Release's notes lists the tokens renamed, the tokens on their way out and every value that changed in each theme, density, text size and layout.
- **Checker.** It lists every design token a project still uses that is on its way out, with the name to use instead. The list isn't a finding, so the project still passes.
- **Showroom.** Each foundation page lists its tokens on their way out under their own heading, each with what to use instead.
- **Read-only fields.** The input, text area, search field and select have a read-only look. The field sits flat on the page with a faint edge and doesn't lift on hover. It keeps its place in the Tab order, and its value can be selected and copied. A read-only select doesn't open, and a read-only search field shows no clear button or key hint. Set `readOnly` on the control, or on the field around it.
- **Field.** It takes `disabled` and `readOnly` and passes them to its control. A disabled field dims its label and help text with the control.
- **Select.** `autoComplete` reaches the hidden input that a form sends, so a browser can fill in a country or a title.
- **Names for fields.** In development, an input, text area, search field or select with no name logs a warning in the console. A production build stays quiet.
- **Checkbox and radio errors.** Both take `error`. An empty box or ring gets a red edge, and a ticked one keeps its fill inside a red ring. The control is marked invalid. Say what's wrong in words beside it, as a field's error line does.
- **Checkbox mixed state.** A checkbox whose control is set to mixed (`indeterminate`) shows a dash. Use it on a box over a list whose items are partly ticked. It used to look empty.
- **Switch icon.** `icon` puts a tick on the thumb when the switch is on and a cross when it's off, at the large and medium sizes.
- **Names for dot badges.** In development, a dot badge with no name logs a warning in the console. Give it a word, or `aria-label`, or hide it with `aria-hidden` when the status is written beside it.
- **Toast region.** `ToastRegion` shows a page's toasts in a corner of the window, one under another, and a screen reader announces each as it arrives. Call `useToasts().show()` anywhere inside it. A toast leaves after 6 seconds, unless the pointer is on the region or focus is in it. Danger toasts and toasts with an action stay until they're closed. Escape closes the toast that has focus. Three show at once and the rest wait their turn.
- **Progress bar states.** Leave out the value and the bar shows a detached part of the track and no number, for work whose end isn't known. `state="failed"` leads with a danger icon and the words you give it. The fill stays where the work stopped, and Try again calls `onRetry`. There's a danger tone too.
- **Pixel progress bar.** `type="pixel"` cuts the track into 20 segments and fills whole ones, in every tone, with or without a value.
- **Names for progress bars.** In development, a progress bar with no name logs a warning in the console.
- **Command palette results.** As you type, a screen reader hears how many commands are left, such as "12 results", or the empty text when none match. `resultsText` changes the words.
- **Breadcrumb icons.** Each crumb can show a small icon before its page name, set with `icon`. It's decorative, in the subtle text color, so give every crumb one or none.
- **Sidebar sizes and looks.** `size="sm"` makes every row 32 px tall, with 14 px text and 16 px icons, for a denser application. `look="flat"` draws the panel square on the page's own surface, with no shadow and a hairline along its end edge. Use it for a sidebar that runs flush to the window's edges.
- **Chosen table rows.** A row ticked in a selectable table takes its own fill, so a choice stands out down the list. The ticked checkbox still says so without color, and the row's descriptions turn one step darker to stay readable on the fill.
- **Code block actions.** An action can be `disabled`. It's drawn faint and takes no press.
- **Code colors.** Give a code block its `language` and each kind of code takes its own color, much as a code editor shows it. Words that steer, such as `import` and `return`, are purple. Words that declare, such as `const` and `function`, and tags and selectors are blue. Text in quotes is orange, numbers green, function names yellow, types and components teal, and properties and keys light blue. Comments and punctuation are gray. It reads CSS, HTML, JavaScript and TypeScript with or without JSX, JSON and shell commands. Each color is a design token, `color/code/keyword` and the rest, and each reads as text on the code block in both themes. Code in another language stays one color. A page built without React can use the same highlighter, which sits beside the component.
- **Line numbers.** A code block numbers its lines in a quiet column before the code. A one-line command shows no number, and `lineNumbers={false}` turns them off. The numbers are never read aloud, selected or copied.
- **Purple, pink and teal.** Three new color families with 11 steps each, on the same contrast steps as the others. Charts and code use them.
- **Pagination select size.** `selectSize="sm"` makes the select 32 px tall, for the range type in a table's foot, where every control is that height.
- **Dropdown.** It opens on the side with room, so near the foot of the window it opens above its button. A long list stops at 320 px and scrolls. A soft shade at its foot says more items wait below. It now shows over the whole page: a box that hides its overflow no longer cuts it off. As the page scrolls, it stays beside its button.
- **Field message.** The line under a control or a group of choices is help, a warning or an error. The warning and the error lead with an icon, so neither shows by color alone, and an error is read out as it appears. The field draws its own line with it.
- **Field group.** Several radios, checkboxes or choice cards sit under one question, in a fieldset whose legend names the group. Help goes under the question and one error message under the choices. The choices take the group's name, error and required state, so you write each of them once. They stack, or sit in a row that wraps when the labels are short.
- **Choice card.** One choice is drawn as a card, with a title, a line under it and a radio or checkbox mark. A press anywhere on the card picks it. A picked card gets a brand edge as well as a filled mark, so the choice never shows by color alone.
- **Side-by-side field.** `layout="side-by-side"` puts the label on the left of a 200 px control, for a column of settings. That width is the new `size/field/control/width` design token. Give the control `size="sm"`. In a narrow space the field stacks.
- **Input slots.** `leadingContent` puts something before the value, such as an avatar or a unit. `trailingAction` puts an action after it, such as a small button that copies the value. Left out, neither takes any room.
- **Large search field.** `size="lg"` is 48 px tall with larger text, for a search that leads a page.
- **Lines under radio and checkbox labels.** `description` adds a line under the label. A screen reader reads it after the choice's name, not as part of it.
- **Spinner.** A small ring of two arcs that turns once a second, for a wait with no known end, alone or beside its words. The button, toolbar, file row, filter bar and combobox show the same ring while they wait. The words are always read aloud, and `label` shows them. When the reader asks for less motion, the ring stands still and the words show.
- **Busy button.** `loading` turns a spinner in the middle of a button while its action runs. The button keeps its width, its name and the focus, and tells a screen reader it's busy. A click, Enter or Space does nothing until the page clears it.
- **Extra-small icon button.** `size="xs"` is a 24 px ghost button with a 12 px icon. It sits beside text, such as a help button in a table heading. It takes the ghost tone and an icon alone; the wrapper refuses anything else.
- **Toggle button.** A button that stays on or off, such as bold text or a layer on a map. Off, it's the outline button. On, it sinks into the page at the same size. A screen reader hears whether it's pressed.
- **Split button.** A main action and a caret button joined in one bar. The caret opens a menu of related actions. It comes in brand, secondary and outline, and it takes the place of a `merged` button group built around a dropdown.
- **Button note.** A button with a short line of quiet words beside it, under it, or at the end of a page header. The line says what the button does, or why it can't be pressed now. It's read after the button's name, and a disabled button stays in the Tab order so its reason can be reached. The note's width is the new `size/button-note/width` design token.
- **Password field.** A field for a password, with an eye button at its end that shows what was typed and hides it again. The button says what it will do: "Show password" or "Hide password". Pasting always works, and the browser's password manager still fills it. Sending the form hides the password first.
- **Number field.** A field for a quantity, with its unit and minus and plus buttons. The arrow keys step it too, and it stays between its lowest and highest values. It reads numbers the way the reader's language writes them, so "1,5" works where that means one and a half. A screen reader hears it as a number field, with its value and its unit.
- **Field warnings.** `warning` puts a line with a warning sign under a field, for something to notice that isn't an error, such as Caps Lock being on. A screen reader reads it out when it appears.
- **List.** Rows of one kind under a title. Plain, bulleted and numbered lists are text, and a numbered row's second line lines up under its words. Navigation rows are links; the current one sits on a lighter fill with a rim and a bolder title. Action rows are buttons, or hold a button at their end. Selectable rows are options a reader picks: the arrow keys move, Space or Enter picks. A picked row shows a tick on a see-through gray fill. Rows come in 2 heights, 40 and 48 px, with dividers if you want them.
- **Description list.** The facts about one thing, each name with its value, stacked or side by side. A row can end with a link such as Change, which a screen reader names after its row: "Change Email address". A missing value says "Not provided", a hidden one says "Hidden", and one still loading shows a line of skeleton. Side by side stacks in a narrow space.
- **Tooltip beside its control.** Give a tooltip its control as `trigger` and it shows itself. It appears a moment after the mouse rests on the control, and at once when the control gets the keyboard focus. Moving the pointer onto the bubble keeps it open, and Escape closes it without moving the focus. The arrow names the side it prefers. With no room there, the bubble flips to the other side, and the arrow still points at the control. Nothing around it cuts it off. A touch never shows it, so its words must be found elsewhere too.
- **Popover above its button.** `side="above"` opens the panel over its button. Near the foot of the window it opens above on its own, and near an edge it moves inward. Nothing around it cuts it off any more, and a panel taller than the window scrolls inside itself.
- **Names in a closed sidebar.** Kept closed, the sidebar shows an item's name in a tooltip beside the column when the item is pointed at or focused.
- **Icon-only segments.** `content="icon"` shows each choice's icon alone, or a short word set with `short` for a choice without one. Its label is still its name, and a tooltip shows it on pointing and focus. `content="description"` puts a short line under each label, set with `description`, and the bar grows to hold it.
- **Theme switch names.** Pointing at an icon or focusing it shows its name in a tooltip.
- **Label help.** The info icon's help shows in a tooltip over it on pointing, and while the field it names has the keyboard focus.
- **Combobox.** A box to type in that suggests matches from a list. Typing narrows the list under it, the arrow keys move through it, and Enter picks. Escape puts back what was there, and Tab leaves without picking. With `selection="multiple"`, each pick becomes a chip with a cross, and Backspace in an empty box removes the last one. A screen reader hears how many matches there are as the list changes.
- **Combobox list states.** A page that finds matches itself, such as a search on a server, sets `filter="none"` and `status`. The list then says it's loading beside a turning ring, or that loading failed, and says so when nothing matches. It never shows an empty panel.
- **Date and time picker.** A field for a date, a time, or both. The reader types a date their own way, such as 03/27/2026 in the United States or 27.3.26 in Germany. Or they pick it from a small calendar that opens under the field. When they leave the field, a date it can read is written again the usual way. Anything else stays as typed, for them to fix. The value always takes one form: an ISO date, a 24-hour time, or both joined by T. When there's none, `onChange` says why, so the page can word its error. On a phone the calendar opens in a small modal. `DateFormatExample` writes the format for the help text the reader's way. The date field's least width and the time field's width are the new `size/date-picker/date-min-width` and `size/date-picker/time-width` design tokens.
- **Calendar.** A month of days to pick a date from, with buttons to the months on either side. The arrow keys move by day and week, Page Up and Page Down by month, and Home and End to the week's ends. Today has a ring and the chosen day a brand fill. A day that can't be picked is struck through, and its reason is read out. The month and the weekdays follow the reader's language, and the calendar spreads across the width it's given. With `selection="range"` it picks a first and a last day instead. Both are marked, and a band joins the days between them, across weeks and at any width; it follows the pointer or the keys until the second pick. A clicked day shows no focus ring; the ring shows when the keys move it.
- **File upload.** A place to choose files or drop them. The button opens the browser's own file picker, with or without script. A drop zone also takes files dropped on it. While they're held over it, its edge turns red and it says "Drop to add". A line under the title says what's accepted before anyone chooses. Each chosen file gets a row below with its progress, then whether it went through. A screen reader hears each file arrive, finish, fail or go, but not every percent. The wrapper uploads nothing. It hands over the chosen files and draws the rows the page keeps. `type="button-only"` is the button over the same line, for narrow places.
- **File row.** One chosen file as a card. It shows an icon for the file's type, its name, its size and its state in words with an icon. When a long name is cut short, the extension stays whole. While it uploads it shows how much has gone, a turning ring and a progress bar. Its buttons are named with the file: Remove, Cancel, Try again or Delete, each shown only when the page can do it.
- **Slider looks.** Two looks beside the default ticks. `look="standard"` is a thin rounded line, red up to a round thumb. `look="fill"` is a thick bar filled red up to a thin light handle. Fine marks sit under it, between the lowest and highest values, and `showMarks={false}` leaves them out. Its focus ring goes round the whole bar.
- **Slider number box.** `numberBox` puts a small box beside the slider for typing an exact value, one at each end for a range. Enter, or leaving the box, moves the thumb there, kept inside the limits and rounded to the step. Moving the thumb changes the box. A screen reader hears it as a number field with the slider's name.
- **Toolbar.** A named bar of tools for one view, selection or editor. What it acts on comes first. Then come 1 or 2 groups of tools, the overflow menu and one main action. Every control in it is the small size, so the bar is 48 px tall. `placement="docked"` lays it flat across the top of a panel. A keyboard reaches the bar with one Tab. The arrow keys move along it, and Home and End go to its ends. A search field or a list inside it keeps its own Tab stop, so typing works as usual. The selection's count, a status and the result count are read out when they change. Some pieces come ready, such as the selection, a status and the overflow menu. A setting's value opens a slider, and a second row shows the filters applied with the result count. In a narrow space, parts marked `wide-only` go and parts marked `narrow-only` come.
- **Filter bar.** Search, filters, sort and Clear all together above a list or a table. Each filter applied shows as a chip with a cross, and a line under them says how many results are left. A screen reader hears the new count each time it changes, and "Updating results" while they load. It's a search landmark, and every control in it is its own Tab stop. The filters button says its count in words. Remove a chip and focus moves to the next one. In a narrow space the sort goes, and a page can open its filters in a drawer instead.
- **Stepper.** Shows where the reader is in a task of 3 or more steps in order, such as a checkout. Each step has a mark, its name and a short status line. A line runs on to the next step. The mark is a number, a check once the step is done, or a warning sign when something needs fixing. The current step has the brand fill. A finished step can be a link back to it. A screen reader hears which step is current and each step's status in words. Lay it out across or down, or as "Step 2 of 4" with the step's name and a slim track. Laid out across, it gives that summary by itself in a narrow space.
- **Timeline.** Things that happened, one after another, such as a project's activity or a deploy. Each event has a dot for its kind, what happened, when, and who did it, with an optional detail line in code type. A line joins the events, and the last one has none below it. A screen reader hears the kind in words before the title, so the dot's color is never the only sign.
- **Splitter.** The line between two panes that the reader drags to give one pane more room, such as a list beside its open message. It also moves with the arrow keys, 16 px a press, and Home and End give the pane its smallest and largest size. It stops at both. The line runs across or down, with an optional grip in the middle. Under the pointer it takes a light fill; while it's dragged it turns brand and twice as thick. A screen reader hears a separator, its name and how far it's moved, as a percentage. You keep the size and lay out the panes. In a narrow space the splitter isn't shown, so stack the panes there.
- **Tree view.** Folders and files, or anything that nests, opened level by level. Each row has a caret, an icon and its name, with an optional count and a dot for a changed item. Each level steps further in, with a fine line under each open folder. The tree is one Tab stop. Up and Down move, Right opens a folder or steps into it, and Left closes it or steps out. Typing a name's first letters jumps to it. Enter or a click chooses a row and opens or closes a folder. The chosen row gets the selected fill and a bolder name. A screen reader hears a tree, each row's level, and whether a folder is open.
- **Chart colors on the Color page.** A new Data colors section shows the colors charts draw in, grouped by job. There's 1 color for a single series and 8 for different series, in a fixed order. There's a scale from less to more, a scale out from a gray middle, and a reference line. Each pair of series colors that sit side by side is measured as people with each common kind of color blindness see it.
- **Sparkline.** A small line beside a figure that shows how it moved over the last days or weeks. It ends in a dot on the newest value, with or without a soft fill under it. Give it your values and it draws itself. The figure beside it says what matters, so a screen reader skips the line unless you give it a summary.
- **Legend item.** Names one series of a chart: a small square in its color, its name, and its value if you show one. Put them in a list for a chart's legend. 8 colors go in a fixed order, a muted gray covers everything else, and 1 color serves a chart with a single series.
- **Uptime bar.** A strip of days, one bar each, green when a site was up, amber for an incident and red for an outage. Under it are the start, the share up, such as "99.9% up", and the end. A screen reader hears the share up and which days went wrong.
- **Heatmap.** A grid of days, a column per week, each day's square shaded from none to most. The months sit above the grid. A summary such as "141 days with work" and a scale from less to more sit below it. A screen reader reads the same values in a table, a week to a row. In a narrow space it shows the last 13 weeks.
- **Line chart.** A trend over time, such as spend per day. Draw one line, add a soft area under it, or set this week against last week as a gray dashed line. The value axis starts at zero and climbs in round steps under light grid lines. Mark one value to give it a dot, a line down to the axis, and its day and amount. With many values, label every seventh one; the last label always shows. A screen reader hears your summary and reads every value in a table. You can show that table under the chart too. The plot's height is the new `size/chart/plot-height` design token.
- **Bar chart.** Amounts side by side, such as a week of days or a month. Plain bars can draw today's a shade darker. Stacked bars split each amount by kind, with a legend in the order they stack. 8 kinds get their own colors, and the rest are gathered as Other, in gray. A month's bars sit closer together. A screen reader hears your summary and reads each value and total in a table, which you can also show.
- **Donut chart.** 2 to 8 parts of a whole as a ring. The total is in the middle with a caption such as "7 days", and a legend beside it names each part with its value. A ninth part and the rest are gathered as Other, in gray. In a narrow space the legend moves under the ring. A screen reader hears your summary, the legend and a table with each part's share. The ring's size is the new `size/chart/donut` design token.
- **Status dot.** A small dot in a status' color, with the status in words beside it, such as "Online" or "Failed". It comes in success, info, warning, danger and neutral. A screen reader hears the words. A dot alone needs a name, and in development it warns when it has none.
- **Avatar with name.** A person's avatar with their name beside it, and an optional second line for their role or a date. Use it for a byline, a comment's author or a task's owner. It comes in 4 sizes, from 24 to 64 px, and the text grows with the avatar. The avatar is decoration, since the name is written out.
- **Avatar group.** A few overlapping avatars for the people on a task or a thread, then a count of the rest, such as "+3". The group is a list named by how many people it holds. Each face takes the person's name, and a screen reader hears the count as "and 3 more".
- **Picture tile.** A button with a picture on top and a short label under it. Use a gallery of them to choose a look, a preset or a template. The picture is 4:3 or square. The chosen tile shows a stronger edge and a tick, and a screen reader hears it as pressed. Each tile fills its cell, so a grid of them wraps.
- **Stat.** One figure with its name above it and a line of what it means under it. Think of 4 pull requests waiting for a review. It comes large or small. Give it `href` and the figure turns into a link that the whole tile follows. A screen reader hears the name with the figure. A status dot before the name marks a figure that needs you, with its meaning in words.
- **Page header.** The top of one page. It holds small breadcrumbs, the page's one main heading, a short introduction and the actions for the whole page. A page about one thing adds its status beside the title and a line of facts under it. Tabs for the page's views can end it. In a narrow space, the main action fills the row and the others go behind More actions. While the page loads, skeleton lines stand in for the words at their own height, so nothing moves when the page arrives.
- **Section heading.** The heading row of a section or a panel. It holds the title, a count beside it, a quiet line such as how fresh it is, and one action at its end. The count sits outside the heading, so a screen reader hears "Waiting on you", then "3 waiting". In a narrow space the action moves under the line.
- **Empty state.** The words that fill an area when its content is missing or failed to load. It names the cause and offers the step that fixes it, such as Clear filters for a search with no results. It comes inline, centred, or as a whole page, with a warning or danger tone for the icon. An error on the server can show a reference to quote to support. With `announce`, a screen reader hears it appear after a search.
- **Error summary.** A box at the top of a form sent with mistakes. It lists each one as a link to its field, in the words the field shows. It takes focus as it appears, so a screen reader reads its heading straight away. Each link moves focus to its field.
- **Meter.** A short bar for how full something is inside a known range, such as storage used. It's built on the progress bar, with a label and a value above it. The fill comes in the chart color, success, warning or danger, and you choose it. A screen reader hears it as a meter with its value. Use the progress bar for how far along a task is.
- **Progress ring.** A ring that fills clockwise from the top, with the percentage in the middle, and turns green at the end. The small ring is thinner and leaves the number out, for list rows. A screen reader hears it as progress. Its 2 sizes are the new `size/progress-ring/md` and `size/progress-ring/sm` design tokens.
- **Board.** Lanes of cards side by side, such as one per project. When the lanes run past the screen, the board scrolls sideways inside itself, and the keyboard can reach and scroll it. On a phone the lanes stack, one under another, and nothing scrolls sideways.
- **Board column.** One lane of a board, pressed into the page. Its head has a title, a capacity meter and an add button. Under it, cards sit in groups, each with a status dot, a label and a count, and an optional "Show all". A screen reader hears each lane as a region named by its title and each group as a list. Give a column a height and it scrolls inside itself.
- **Capacity meter.** A row of 2 to 4 short bars, one per place, filled as places are taken. The same count follows in words, such as "1 of 2 places". A screen reader hears it as a meter with those words.
- **Log.** What a program prints as it runs, in a sunken box that keeps the newest line in view. Scroll up to read and it stops following. "Jump to latest" brings you back. Lines wrap, so nothing scrolls sideways. A screen reader hears when the output starts and when it finishes, never every line, plus a short status the page can set.
- **Picture logo.** The logo takes a site's own logo files, which keep their own colors. Give the whole logo, the mark and the wordmark, each with a dark version for the dark theme. The header, footer, app bar and sidebar take them as `logoPicture`. Each picture's text alternative is the logo's name.
- **Skeleton shapes and sizes.** There are 7 new shapes. An icon, a badge, an input and a paragraph that ends on a shorter line. And 3 blocks, a list item, a card and a table row, built from the other shapes. Every shape comes in small, medium and large, to match the text or control it stands in for.
- **Card header, body and footer.** The card's 3 parts come as `CardHeader`, `CardBody` and `CardFooter`. A header holds a title, an icon, a person, a number or a terminal's window bar, in 3 sizes. A count, a status, a link, an arrow and a menu button can sit beside the title. A body holds text, or any other component in its slot: a stat, a list, a description list, a progress bar, code, a chart or an empty state. A footer sits under a rule you can leave out. It holds buttons, a link, one wide button, a person, tags, people, a total or a note.
- **A card that opens something.** Give a card `href` or `onOpen` and its title turns into one link or button, and a press anywhere on the card follows it. Its edge turns strong on hover, and the focus ring goes round the whole card. Set `dragged` while a page moves a card, as on a board, and it lifts off its lane. A board's items are these cards.
- **Lists in an alert.** An alert's description can hold several paragraphs or a short bulleted list, as well as a sentence. It keeps the description's text style.
- **Link size from its text.** `size="inherit"` takes the size and face of the text around it, as in a heading or a card title, and keeps the underline. Its icon takes the text's size too.
- **Small accordion.** `size="sm"` has a 14 px title and text, tighter padding and a 16 px caret, for a narrow column such as a settings panel. It comes in both looks.
- **Command descriptions.** A command can show a second line under its label with `description`, such as what it opens or a snippet of the page it finds. Wrap the words that match the search in `mark` and they show one weight bolder. Typing filters on the description too.
- **Line tabs.** `look="line"` draws tabs with no well, as tall as the boxed tabs of their size. A line runs under the row, and a brand underline sits under the chosen tab and slides from tab to tab. In a vertical bar the chosen tab gets a side bar instead.
- **Counts and dots on navigation.** Navigation items, app bar and header links, and sidebar items and children take `count` and `dot`. A count is a small badge, such as the number of open issues. A dot says something there changed. Both are read with the item's name, as "Issues, 18". The dot's words are "changed" unless `dotLabel` says otherwise. In the sidebar's column of icons the count joins the icon's name, and the dot sits on the icon's corner.
- **Folded breadcrumbs.** `overflow="collapsed"` keeps the first crumb, the parent and the current page of a long trail. A small "more" button stands for the pages between them and opens them as a list of links.
- **Blocks.** A new section of the Showroom, after Components, with ready-made arrangements of components to copy into your project: the stat strip, the bar list, the goal row and the usage meter. Each page draws its examples with the real components and gives their markup, React and stylesheet; rename the `site-` prefix to your own.
- **Diff stat.** Shows how much a change touched, the lines added and removed, such as "+128 −12", with five small squares for the balance. A screen reader hears one sentence, such as "128 lines added, 12 lines removed".
- **Color swatch.** One color shown as a small square or dot, in four sizes. A see-through color shows a checkerboard behind it, and no color shows as a crossed-out square. A screen reader hears the color in words, such as "vibrant blue", or the name you give it.
- **Color slider.** Changes one part of a color (its hue, saturation, lightness or opacity) by dragging along a strip of the colors it moves through. The arrow keys move it too, and a screen reader hears the value and the color in words.
- **Color area.** Picks saturation and brightness at once by dragging in a square of one hue's colors, or with the arrow keys. It fills the width it is given, up to its own size.
- **Color swatch picker.** A set of colors to pick one from, in rows that wrap. A ring with a gap marks the chosen color. It is one Tab stop: the arrow keys move between colors, and Space or Enter picks one.
- **Color field.** A text field for a hex color code, with a swatch of the color at its start. It settles the code when you leave the field or press Enter, and puts back the last good color if what you typed isn't one.
- **Color picker.** A field or a swatch that opens a panel to set a color. The panel holds a color area, hue and opacity sliders, the code, an eyedropper in browsers that have one, and saved colors. Each part works from the keyboard and says its value in words. The panel is also available on its own, for a page that places it itself.
- **Color sizes.** Two new size tokens, `size/color-area/width` and `size/color-picker/width`, for the color area and the color picker's panel.
- **App bar and header looks.** Five looks: floating, floating hug, flat with a line along its foot, split into two islands, and centred with the brand in the middle. Two more settings give the bar its own room around it and a frosted blur behind it, and a second row under the bar holds tabs.
- **Folding bars.** Where a whole row doesn't fit in a wide space, the bars fold parts away instead of cutting them off. The app bar folds its action buttons first and then its links; the header folds its links. The menu button opens them under the bar, and the call to action and the theme switch stay. `fold={false}` keeps every part in the row.
- **App bar parts.** A badge after the brand that stays when the logo is off. A start that can hold something else, such as a back button and a title. A middle that can hold tabs, a search field or a title in place of the links. A size setting for the links.
- **Agent card block.** One agent's job on a card. It shows the state in words (working, waiting on you, queued, finished or failed), the task, time and cost, how far along it is, and the button that fits. A card that waits on you gets the warning edge.
- **Project card block.** One project at a glance: its stage in words, three figures, a line of recent work and the places it's live. An idea not built yet shows as a dashed, sunken box.
- **Site card block.** One site at a glance: up, slow or down in words, the version it shows and three figures. Its last 30 days show as an uptime bar. A site that's down gets the danger edge.
- **Quote card block.** What a customer said, in their own words, under a quotation mark, with who said it: their initials or picture, name and role.
- **Price card block.** One plan at a glance: its name and who it's for, its price, what it includes with a tick before each line, and one button across the card. The plan the reader already has takes the card's selected edge and says so in a badge.
- **Settings panel block.** A column of settings beside what they change: a choice at the top, groups that open and close, and a footer that counts and resets the changes.
- **File tree block.** A project's files in a panel, with the line it shows, a count of changes and when it was read. A long tree scrolls inside the panel.
- **Diagram node block.** One box of a how-it-works diagram, in five kinds: part, input, output, store and outside. It can be chosen, and has a dot on each side for the arrows.
- **Footer looks.** Six looks: columns, minimal, centred, floating (on a raised card), call to action (a card asking for one action above the rest) and big wordmark (the name as wide as the footer). The brand can carry a line about the site and a newsletter sign-up. The legal strip can carry a status, a language button, the theme switch, a link back to the top and fine print under it.
- **Footer settings.** Switches for the divider above the legal strip, a background band behind the footer, and the footer's own room: its content held to the content width with space around it.
- **Footer legal links at the end.** `legal="end"` moves the legal links to the end of the legal strip in a wide space, just before the extras. The copyright and its tagline stay at the start. On a phone the strip stacks as before.
- **Even footer columns.** `column-width="equal"` makes every column of links as wide as the widest, with the same gap between them. Where they don't all fit beside the brand, they stand in 2 even rows, so 4 columns show as 2 and 2. No column is left alone under the rest. It works without script.
- **Table headings.** A column of figures can line up at the end, its sort arrow before the label. A heading can have a filter button that opens a list of choices that tick; while filters apply, a count shows beside it and its name says the count.
- **Table rows.** Rows can be pinned (a brand edge and a pin), highlighted with a tint, or set off with a stronger rule above. Group headings with a count split the rows into groups.
- **Table rows that open.** A caret at the start of a row opens a detail row under it, across every column, for notes, a history or a small form.
- **Table cells.** A prose column wraps its sentences within a readable width. A cell can show a figure with a short bar after it.
- **Color range.** A strip of a color range's steps, each with its swatch, its name and its contrast against white. The step in use is ringed, and a reader can pick a step when the page allows it.
- **Contrast pair.** Two colors drawn as text on its background, with their contrast ratio and the mark it earns: AAA, AA, AA large or fails, worked out from the colors.
- **Curve editor.** Shapes an animation's easing curve. Drag its two handles, move them with the arrow keys, or type its four numbers.
- **Shadow editor.** Edits a shadow layer by layer, with a live preview: offsets, blur, spread, color and opacity. Layers can be added, removed and put in a new order with the keyboard or by dragging.
- **Ruler.** Sets a preview's width along a band shaded by layout state, with the breakpoints, common screen widths and a handle that moves with the arrow keys.
- **Corner sample.** Draws one corner at any radius, for lists of corner steps.
- **Search field.** `clearLabel` names the clear button for a page in another language. It stays "Clear search" unless given.
- **Field group.** The group can keep track of which radio is chosen. Give it `value` and `onChange`, which hears the chosen value each time, or `defaultValue` to let the group keep the choice itself. Each radio and each radio choice card is checked when its value matches.
- **Checkbox.** `indeterminate` shows the mixed state, the dash on a box over a partly ticked list, with no script of your own. A box with no words beside it, such as a table row's, can be named with `aria-label` alone.
- **Field and your own controls.** A control inside a component of your own still gets the field's id, label, help and error, and its required, disabled and read-only state, even when your component passes nothing on.
- **Field message.** With no words it draws an empty place that words can arrive in, so a status line is heard when it appears. `iconClassName` adds classes to its icon.
- **Visually hidden.** The class `smbk-visually-hidden` hides an element from view and keeps it for screen readers and the keyboard, with the same rule the components use for their own hidden words.
- **Words in any language.** Every word a component shows or says by itself, such as a close button's name, a pagination's "Page 3" or a command palette's key hints, can be given in the page's language. Each keeps its English unless the page gives its own.
- **Heading levels.** The modal, the drawer, the footer, the sidebar's group labels and the board column take a heading level, so their titles fit the page's outline. Each keeps the level it had unless given another.
- **Tabs as links.** `TabsNav` draws the tabs as a navigation of links, for a few pages of one subject that each have their own address. The link to the page shown is marked as the current page. Tab moves from link to link, and there are no panels, so a reader can open any page in a new browser tab. Past `max` links, the rest go behind a More tab at the end of the row that opens a menu of them. While the page shown is one of them, More takes its name.
- **App bar tabs.** `nav-type="tabs"` draws the bar's links as small line tabs that fill its height, with the current page's underline on the bar's foot. The bar is then 64 px tall. `links="start"` puts the links right after the brand. `sidebar-start` makes the start as wide as the sidebar under the bar, so the links begin at the sidebar's edge.
- **Download for plain HTML.** Each Release on GitHub has the files a site needs as one zip, `simbolik-<version>.zip`: the stylesheet, the fonts, the icons and the React wrappers, under one folder called `design-system`. Unzip it into a site and link the stylesheet. There is no clone, no install and no build.
- **Quick start.** The README now opens with five lines to paste into an empty page beside the unzipped download: three stylesheet links, a dark theme and one button.
- **React on the Docs page.** A short React section says how to make React and React Aria come from your own packages, with the `package.json` lines and the Vite setting (`resolve.dedupe`) written out from the design system's own packages.
- **Open in an AI chat.** The copy menu on each Showroom page ends with an item that opens a new chat with an AI assistant, with a short prompt that points at the page's markdown copy.
- **Component catalog.** The Showroom publishes `components.json`, one file listing every component with its Status, classes, props and the choices each takes. It is made from the components' own manifests at every build, and `llms.txt` points at it.

### Changed

- **Component notes.** Each component's notes link the other components they name, on GitHub as on the Showroom. That covers the ones they send you to instead and their list of related ones. Their accessibility notes come in 3 short lists: what the component does for you, what you must do, and how to test it. A table of its keys follows, for each component that takes keys.
- **Showroom: component pages.** Each page leads with what a reader comes for. The title has its badges beside it, the stage fits the component, and the code folds away under it. A table lists every choice with its values, its default and what it does. Each React example starts with its import lines, and the markup puts one element on each line. Next come the guidelines, the accessibility notes and the related components. The stylesheet, the design tokens and the manifest sit closed at the foot. Once a Release has put the component on GitHub, a link leads to its folder there. The preview's toolbar names every setting and keeps the component's choices at its start and the view at its end. A long list of choices goes into one Customize panel. On a phone, one Customize button opens them all in a sheet.
- **Showroom: foundation pages.** Each page opens with what it shows, such as the color roles, the type scale or a ramp of its sizes. Its guidelines follow, then its design tokens in groups, closed until opened. Each primitive color family is one strip of its steps, and a typography preset fits on one line. The color page's contrast check opens with how many pairs pass in each theme. The foundations follow one order in 3 groups: Core, Shape and depth, and Behavior.
- **Showroom: block pages.** Each page leads with its examples. Each example's code folds under it, with the markup one element per line and the React with its import lines. The components it's built from follow as links, then its guidelines and its accessibility in 3 short lists. Its stylesheet sits closed at the foot.
- **Showroom: finding your way.** The Components page groups the components into the sidebar's categories, each with its count, and a filter narrows them as you type. On a phone the cards stand 2 to a row. The sidebar shows how many components each category holds and keeps the current page in view. The phone menu has the categories too. Previous and next follow the sidebar's order and say when they cross into another category. A status badge leads to what that status promises.
- **Showroom: shorter pages.** A component page shows its first 6 examples, and a button shows the rest. The Releases page lists the releases, with the notes not released yet folded at its top.
- **Showroom: Docs.** The Docs are 8 short pages, from an introduction and a quick start to version and Status and working with AI assistants. Each page has a sidebar, a list of its sections, a link to the next page and its own markdown copy. A link to a part of the old single page still lands on that part.
- **Modal, drawer and command palette.** Each can start open on its own with `defaultOpen`, and calls `onOpenChange(false)` when it asks to close, as the popover and the dropdown do. Given `open` or `defaultOpen`, the command palette sits over the page.
- **Status colors.** The badge, tag, avatar and checkbox now set their color with `tone`, as the alert, the chip and the rest already did. It was `type` on the badge, `scheme` on the tag and the avatar, and `variant` on the checkbox. Their classes become `smbk-<block>--tone-<value>`. The plain tone is `default` everywhere, where the status dot, the empty state, the avatar and the timeline said `neutral`. The avatar's dark fill is `tone="inverse"`.
- **Toolbar.** Its status draws the status dot. In dark, the dot is a shade different.
- **Theme switch.** It's now the segmented control's new `theme` look: its markup is `smbk-theme-switch` beside the segmented control's classes. It looks the same.
- **Toggle button.** The button's own stylesheet draws it, so its markup is the button's classes, `smbk-toggle-button` and `aria-pressed`.
- **Chip.** A chip you can switch on is drawn on from `aria-pressed="true"`.
- **Gliding hover.** In the dropdown, select, combobox, command palette, sidebar and pressable lists, one hover fill slides from row to row with a mouse, instead of each row lighting up on its own. Between rows it lights the nearest one, and a click there presses it. The keyboard's highlight is unchanged, and touch screens show no hover fill.
- **Bold labels hold still.** A nav item, sidebar row, list row, tree row or command whose label turns bold when it becomes current or chosen keeps its width, so nothing beside it moves. Markup written by hand repeats the label's words in its `data-label` attribute.
- **Menus and tooltips.** Menus, the select's and combobox's lists and popovers grow out of their opener on the side they open, upward when they open above. Tooltips slide a short way out of their target.
- **Code block.** When an action's icon changes, such as copy turning into a tick, the two icons cross-fade in place instead of swapping at once.
- **Table of contents.** Children hang from a thin tree line, and the items sit closer, touching. The section in view, and any item under the pointer, is marked in brand red: a line down a parent's edge, or its stretch of a child's tree line.
- **Table row height.** A row is at least 40 px tall and grows with what it holds. A value over its description keeps 8 px above and below, so its two lines no longer run up to the lines between rows. An icon before a value sits 6 px from it instead of 4.
- **Showroom code.** Every code view in the Showroom colors its code and numbers its lines: the markup, the React, the stylesheet, the tokens and the manifest of each component and block, and the examples on the Docs pages.
- **Code block look.** The bar and the well are lighter. The file name sits after a file icon, in the label's quiet body text, and the bar is 40 px tall, or 48 px with tabs. With tabs, the bar shows the tabs and no file name. In markup written by hand, give the label part the label's classes, `smbk-label smbk-label--tone-subtle`, and put the name in `smbk-label__text`.
- **Reduced motion.** When a reader asks for less motion, things still fade in and out, but nothing slides, grows or turns: a modal or toast fades in place, and a drawer appears where it stands and fades in.
- **Switch.** With a mouse, the thumb stretches a little when pointed at and squashes when pressed, so the switch answers before it flips. The switch itself never moves.
- **Button.** A pressed button draws its fill and edge in by a hairline on every side, so it reads as pushed in at any width. Its size and focus ring stay the same. Buttons in a segmented bar and a toggle that is on keep their own pressed look.
- **Charts.** The bar, line and donut charts and the sparkline draw themselves in the first time they come into view: bars grow up one after another, lines are uncovered from left to right, and the ring sweeps round. A chart already on screen as the page opens plays from its first frame. With reduced motion they appear at once. Pointing at a bar or a ring part fades the others to half, and moving from bar to bar or part to part no longer flickers.
- **Chart tooltips.** Pointing at a bar, a ring part, a heatmap day or an uptime bar shows the browser's own tooltip with its label and value, such as "Saturday: $352". A stacked bar lists each kind and the total, and a ring part adds its share. Screen readers hear nothing new, since they already read every value in the table or the summary.
- **Dark theme rim.** The light edge that makes fields, cards, chosen pills and panels look lit is fainter in the dark theme: white at 5%, down from 10%. The fainter edge on avatars, key caps, tags, the slider's thumb and a field's well is white at 3%, down from 5%. White at 3% is a new design token, `color/alpha/white/3`.
- **Hover fills.** The outline and ghost buttons' hover fills are see-through grays, so they tint whatever they sit on, a card or a toolbar, instead of laying a solid gray over it. The ghost fill is a little stronger than the outline one, most of all in the dark theme. Calendar days, list rows, outline chips, stepper steps, the code block's buttons and the splitter use the same fills.
- **Getting started.** The README and the Docs page now build the stylesheet, the fonts and the icons with `npm run css:bundle`. A site copies the folders it needs from there.
- **Component and foundation pages.** They now hold only what someone using the system needs. The notes on how each was built from Figma are gone. The few lines a site relies on moved into Behavior, Accessibility or Usage rules.
- **Glossary.** The words the system uses, and the ones it avoids, are now in `GLOSSARY.md`. How names are made is in `docs/`, and what the token build checks and writes is in the README.
- **Design tokens.** Each color in `tokens/` now takes the form the design token standard gives it. It's an object with the color space, three components, an alpha and a six-digit hex. The stylesheets, `output/tokens.ts` and `output/tokens.json` still give each color as hex, and every color is the same as before.
- **Dark theme text.** Secondary text, the quietest text and disabled text are each one gray step darker in the dark theme, so they sit further back from the main text. The light theme is unchanged.
- **Colors.** The palette is rebuilt on one contrast ladder. One gray ramp replaces the four gray families, and a step number now means the same contrast against white in every color family. Most color roles move to a slightly different shade; the light page, card and raised surfaces stay exactly as they were. Fewer pairs fall short of the contrast WCAG asks for: 27 of 208 measurements, down from 33.
- **Text.** Text keeps its full line height, as it does in Figma. Nothing is trimmed to the height of its capital letters any more. Where a component's height comes from its padding, it grows a little; controls with a set height keep it. Body text has a line height of 150%, up from 140%. Heading 2XS is 18 px on phones, down from 20, with a line height of 120%.
- **Labels.** The label styles are set in Geist Medium and sentence case. They used to be Geist Mono in capitals, so a label written in small letters now shows them; write it in sentence case.
- **Design tokens.** Many tokens have new names. Text styles are named by size (`h1` is `heading-xl`, `body-m` is `body-md`), shadows by what they do (`elevation-1` is `elevation-raised`), the destructive action is `danger`, and the edge colors are `rim` and `groove`. The old names are gone, and What breaks lists them.
- **Button.** Each size has its own padding, label and icon: small is 12 px from each side with a 16 px icon, medium 16 with 20, large 24 with 20. Labels use the label style. An icon-only button shows the same icon as a labeled one, one step smaller than before. Medium is now the default size, so a button with no size is 40 px tall, not 48. A disabled button of any tone shares one faint look.
- **Button group.** Separate buttons sit 12 px apart at the large size and 8 px at the others, down from 16. The brand bar's dividers take the brand button's own edge color. The outline bar is as tall as its buttons. Medium is the default size, as for the button.
- **Link.** Every link is underlined, so a link in a sentence never reads as plain words. A link that stands on its own takes the new `standalone` flag, as in a list, a card or a footer. It shows its underline on hover and press only. The icon beside a large link is 20 px, up from 16.
- **Key cap.** Keys are set in Geist Mono again, in the new code styles.
- **Input, text area, search field and select.** A field in error keeps its red edge while it has focus. It also shows a warning icon, so an error is a shape as well as a color. The sizes are now `md` and `sm`. Small text is 14 px from tablet width up. On a phone it's 16 px, so the browser doesn't zoom in when the field takes focus. Icons at either end are the same size, 20 px at md and 16 at sm. At md the gap beside an icon is 8 px, up from 6.
- **Text area.** Its text is 16 px, like the input's, and it starts 2 rows tall, as Figma draws it, not 3. In error, the warning icon sits at the top end.
- **Search field.** It pads like the input, 12 px from each side at md, up from 8. The clear button has a 24 px box, the least a press needs. The key hint shows only while the field is empty, and gives way to the clear button once there's text.
- **Select.** The caret is 20 px at md, up from 16. An open list stops at 320 px and scrolls.
- **Field.** The error message leads with an icon, and a screen reader reads it out as it appears. Help text is 14 px, up from 12. Given `error` with no message, the field shows its help text as the message, with the icon.
- **Label.** The `mono` type is now `small`, set in the small label style. The info icon is 16 px, up from 12, in the faintest text color.
- **Checkbox and radio.** Under the pointer, an empty box or ring darkens its edge and a ticked one darkens its fill. The sizes are now `md` and `sm`. Every row is at least 24 px tall, so it's easy to press.
- **Switch.** An off switch has a filled gray track in place of a faint outline, so it shows on any page. The thumb stays near-white in both themes. An on switch darkens under the pointer, and a disabled one has a faint gray track. Every row is at least 24 px tall.
- **Slider.** The thumb darkens under the pointer and again while pressed. Hiding the label now hides the value beside it too, so no row holds a number on its own. The value bubble shows while the thumb has keyboard focus, as well as while it's pressed. A slider with a hidden label that needs its number in view should show it in its own words. When a value comes from the number box, `onChange` gets the value alone, without the range input's change event.
- **Badge, chip and tag.** They share one scale of heights: 32, 24 and 20 px. Their labels use the label styles, Label MD at 32 and Label SM below. The default badge, chip and tag are a see-through gray with no edge, so they show on any surface. They used to sit on a white fill.
- **Badge.** It pads 12, 8 and 6 px from each side, with icons of 16, 12 and 12 px. The small badge is 20 px tall, up from 16. Numbers take equal-width digits, so a count that changes keeps its place.
- **Chip.** A selected chip shows a tick before its label, so the choice shows by more than its color. Pressed and selected chips sink in, where they used to lift, and the default chip darkens on hover. A 6 px gap separates the avatar or tick, the label and the cross. The cross is 16 px at md and 12 at sm, down from 24 and 20. It sits inside a 24 px box that is easy to press. Its focus ring circles the cross. The sizes are now `md` and `sm`.
- **Tag.** The icon and the cross are 12 px, down from 16. The tag pads 8 px from each side, up from 6, with a 4 px gap. The cross sits inside a 24 px box that adds no width, and its focus ring circles it. The default tag has no shadow. The tones `positive` and `negative` are now `success` and `danger`.
- **Avatar.** Initials take the label styles in the small sizes, Body LG at large and Heading 2XS at the largest.
- **Image placeholder.** It takes the sunken surface and a container's corner, so in dark mode it's near-black, not gray.
- **Logo.** The mark is the same red in both themes. In dark mode it used to turn a lighter, pinker red.
- **Alert and toast.** Each tone has its own icon: a bell, an info circle, a tick, a warning sign and a crossed circle. It's 20 px in the tone's icon color, centered on the title's line. An alert or toast that names its own icon keeps it. The title is set in Label LG and sits right on its text. The padding is 12 px above and below and 16 px at the sides, so both are a little shorter. The cross sits in a 24 px box that is easy to press.
- **Alert.** On a phone, its action goes under the words and lines up with them, so the words keep the full width. Several buttons wrap onto more lines.
- **Banner.** Each tone shows an icon before its message. The neutral tone has a megaphone and the others have the alert's icons. `icon` replaces it, or leaves it out when set to `false`. The strip pads 8 px at the sides, up from 4. On a phone the message wraps beside its icon and the link sits under it, all from the start edge.
- **Progress bar.** The track and the fill are the same height, 4 px or 2 px. The empty track is a light gray pressed into the page, where a thin dark line used to run under a thicker fill. The label takes the main text color, and the percentage has equal-width digits. The sizes are now `md` and `sm`. A value above the maximum is read out as the maximum.
- **Skeleton.** Its shapes are a see-through gray, so they show on the page, a card or a raised panel in both themes. On a light page they used to be almost invisible. The sweep runs 3 times and then rests, so nothing on the page moves by itself for more than 5 seconds. Its medium size is the default. There the title stands in for Heading MD and the label for Label MD, as in the design file, so both are taller. The button skeleton is 40 px tall, down from 48, and 3 times as wide as it is tall. It used to stretch to 480 px. The avatar skeleton keeps its 40 px in the compact density, as the avatar does.
- **Dropdown.** The panel takes the solid overlay surface, white in light mode. Under the pointer or keyboard focus, an item takes a see-through hover fill. It used to sink into a darker surface, which looked like a hole in dark mode. Items touch, with 4 px around the list. A default item is 40 px tall, with 16 px text and a 20 px icon, 12 px from each side. A small one is 32 px, with 14 px text and a 16 px icon, 8 px from each side. Group labels line up with the items. A disabled item dims its key hint along with its words.
- **Dropdown width.** The panel is at least 240 px wide and grows to fit its longest item on one line, up to 320 px. So a long item no longer breaks onto 2 lines, as it did in a header's menu. Past 320 px an item still wraps inside the panel. The limit is the new `size/dropdown/max-width` design token. The select's and the combobox's lists stay as wide as their field.
- **Select.** In an open list, the option the keyboard is on takes the dropdown's new hover fill.
- **Command palette.** The highlighted command sits on a deeper fill and its label turns one weight bolder, so it shows without color. The search box now shows the focus ring while it has focus, so you can see where you are even when nothing matches. The highlighted command no longer does. Each command is 40 px tall, and a group label is the small label style on a 32 px row, set in like the commands. The clear button sits in a 24 px box that is easy to press. See all has no arrow.
- **Modal.** The title is set in Heading 2XS bold, and the icon beside it is 24 px, down from 32. The parts sit 24 px apart, up from 16, and the footer's buttons 12 px apart, down from 16.
- **Drawer.** The panel takes the raised surface, a shade lighter. The title is set in Heading 2XS bold and sits right on its description. The close button is centered on the title's line, and the footer's buttons are 12 px apart, down from 16.
- **Popover.** The panel takes the solid overlay surface, white in light mode, with a container's corner. The title is set in Label LG and sits right on its description. The close button is centered on the title's line, and its cross is the faintest text color.
- **Navigation item.** Each size has its own text, icon, padding and gap. Large is 40 px tall with 16 px text and a 20 px icon, 16 px from each side. Medium is 32 px with 14 px text and a 16 px icon, 12 px from each side. Small is 24 px with 12 px text and a 12 px icon. The current page's label is one weight bolder at the large and medium sizes.
- **Sidebar.** The current item and an open group's item take a see-through gray fill and a bolder label. They show on any panel, and not by color alone. A child item rises under the pointer, as its parent does. Child items are set in 14 px text and touch, with no gap between them.
- **Header.** On a phone, the open menu has one divider under the bar. Its links and its call to action are each 40 px tall and sit 4 px apart. The call to action is medium, down from large. A group's links are set 16 px further in than the link that opens them.
- **Footer.** Each column of links is as wide as its longest link, and the columns sit at the end of the row. The links are 14 px text and sit 4 px apart, down from 8, and each heading lines up with its links' words.
- **Breadcrumbs.** The caret between crumbs follows the size: 16 px at md, up from 12, and 12 at sm. Crumbs and carets sit 6 px apart, up from 4.
- **Pagination.** The current page's number is one weight bolder, so it shows by more than its fill. Page numbers have equal-width digits, so they line up. Skipped pages show as an ellipsis in 14 px text.
- **Segmented control.** The small size writes 14 px text, up from 12. Icons follow the text: 20 px at the large and medium sizes and 16 at the small, each one step up. The large size pads its items 16 px from each side, up from 12.
- **Theme switch.** The medium switch's icons are 20 px, down from 24.
- **Tooltip.** The bubble fits its words. One line is 28 px tall, 4 px over and under its text and 8 at the sides, and longer words wrap at 240 px. The slider's value bubble grows to 28 px with it.
- **Table of contents.** The wide box is drawn like the narrow one. It's 12 px inside, with 12 px between the heading row, the rule and the list, and smaller corners. The heading row starts with a list icon. Each item is 32 px tall and 4 px from the next. The current item's label is one weight bolder, beside its line.
- **Table.** A sorted column shows its direction, with an arrow up when ascending and down when descending. A column that can be sorted but isn't shows both ways. Under the pointer a row takes the see-through hover fill. The sort and copy buttons each give the pointer 24 px to press, and nothing moves to make room. A value sits right on its description. Numbers take equal-width digits, so they line up down a column. The choose-all checkbox matches the rows' subtle one, and a strong rule sits over the foot. In compact density a row is 32 px tall, as the density asks; it used to stay at about 41.
- **Code block.** Code is set in Geist Mono again, in the code style. It had been in the sans face since the labels moved to Geist. Code always reads left to right. Under the pointer or pressed, an action takes the ghost button's fill.
- **Accordion.** The focus ring goes around the whole item, and a flat item lifts to the raised surface while it has focus. The whole heading row opens the item, its padding included.
- **Card.** With the picture behind, the words sit at the card's foot on a dark band, the same in both themes, 16 px inside. Light text stays readable on any photograph. The frosted band it replaces covered the whole picture and was hard to read over a bright one.
- **Showroom.** Pages appear sooner. Your browser and Cloudflare now keep the font stylesheet and the design system's stylesheet. A visit no longer waits 0.3 to 0.5 seconds while the server is asked about each. A new version of either still shows at once.
- **Showroom.** The Components sidebar groups the components into categories, such as Buttons, Inputs and Navigation, that open and close, so the list is short. The sidebars use the small rows. Every component has its own icon in the sidebar and the search, where most of the newer ones shared a cube.
- **Showroom.** A component's Preview holds all its choices in one toolbar along the top of the stage, so the component shows higher up the page. Each choice is a button with its name and value, such as "Tone: Brand", that opens a menu of the values. The size is a row of buttons. The parts and flags are 1 or 2 toggle buttons, or one Options menu to tick when there are more. Desktop or Mobile, the theme and the density are icons, then Reset. Tab reaches the toolbar once and the arrow keys move along it.
- **Button group.** A row of separate buttons wraps onto a second line when it runs out of room, 4 px under the first, and never grows wider than its space. A segmented bar stays on one line. A focused button in a bar sits above its neighbors, so its ring always shows.
- **Toggle button.** A ghost tone, `tone="ghost"`, for a tool among others in a toolbar. Off, it's the ghost button with no fill or edge. On, it sinks into the page as the outline toggle does.
- **Link.** A button can take the link's classes for an action that sits among words and changes the page, such as Clear all. It looks like the link and is announced as a button.
- **Card.** A card now stands on one of 5 surfaces: slab, raised, float, well or outline. It takes one of 5 layouts. Stacked puts the picture on top, side puts it beside the words and behind puts it under them. Panel lays the parts edge to edge with the header on a shaded band, for a dashboard. Compact is the tight card for a grid. The `selected` flag draws a brand edge, `brackets` marks the corners and `warning-edge` and `danger-edge` color the rim. A picture can be an element, such as an image placeholder, and can take a 16:9, 4:3 or 1:1 shape. The plain card changes look to match the design file. Its corners are rounder, at 16 px. The picture sits inside the card's edge with its own small corners. The title is Label LG with a quiet line under it, and the footer sits under one thin rule. The eyebrow is Label SM.
- **Alert.** The description is a `div` now, not a `p`, so it can hold paragraphs and lists. Text on its own looks the same.
- **Showroom top bar.** The bar is flat on the page, with a line along its foot, and the sections are line tabs that fill its height. The logo is smaller, and the logo and the badge take the sidebar's width, so the sections begin where the page does. Search is a button in the bar on every page, and the sidebars no longer hold a search field. Cmd+K or Ctrl+K still opens it anywhere.
- **Line tabs.** Each tab is a step taller, 48 px, or 40 px at the small size. Pointing at a tab fills a rounded row inside it, where it used to draw a gray underline. The chosen tab's underline runs its whole width, and its label is a weight bolder. Icons in line tabs are 20 px, or 16 px small.
- **Tabs.** A badge in a tab is read after a pause, as "Activity, 18". Small tabs set their labels at 14 px, up from 12, as the design draws them. Boxed tabs fill their bar as the segmented control's choices do, 36 px tall in the 40 px bar and 28 in the 32 px one, up from 34 and 26.
- **Sidebar.** A tree line runs down an item's children, from under its icon, turning toward each child's label and ending at the last child. Every sidebar with children shows it.
- **Radius.** The page says that a part that frames or floats takes a container corner. A checkbox, a text area and an accordion item keep a control corner and are never a capsule, and their pages say so too.
- **App bar.** The links sit in the true middle of the bar and are the middle size, a little smaller and closer together. The end group's controls are closer, and there's no divider before the user. On a phone the mark is as tall as the wide logo and the bar has the same inset all round. The open menu has no dividers, with the theme switch last. Pass `size="lg"` for the old links. A bar given `onSearch` and no search field shows its search button in a wide space too, at the start of its end group. A flat bar that hides on scroll sticks flush with the top of the window. A bar with its background off takes the page's own color while it sticks, so nothing shows through it.
- **Dropdown.** In a menu of links, the link to the page being shown has the selected fill and bolder words.
- **Header.** The links are the middle size by default, closer together. The call to action and the theme switch sit closer together, and the three columns a little further apart. Pass `size="lg"` for the old links.
- **Menu button names.** The app bar's and the header's menu button says which menu it opens.
- **Footer on phones.** Each column of links folds into a row that opens and closes, the first one open. The brand follows the rows at the start, and the legal strip stacks at the start under a divider.
- **Footer links.** Social links are small icon buttons. Legal links are small links set closer together, and the strip sits at the start in a wide space. The tagline sits closer to the copyright.
- **Footer look names.** The look called `default` is now `columns`.
- **Table info.** A heading's info is now a small button that opens its explanation in a popover, reachable with Tab. Before, it was an icon only screen readers could read. The setting is the same and earlier markup keeps working; the column gets a little wider.
- **Number field without buttons.** `hideButtons` gives a bare box without the minus and plus buttons, for rows of small number boxes.
- **Touch screens.** On a touch screen every control looks exactly as it does with a mouse. Each takes an invisible press area around it, 44 pixels each way where there is room. Where controls stand closer, the area stops halfway to the next one, so a press never lands on the wrong control. No press area is smaller than 24 pixels each way.
- **Slider.** The larger area that takes a finger now applies on any touch screen, not only in a narrow layout.
- **Table on touch screens.** A table with a pinned first column scrolls what you move to into view beside that column, not under it.
- **Accordion.** Only one item stays open at a time: opening one closes the one that was open. Set `multiple` to let several stay open, as before. Items now grow open and closed smoothly in every browser, not only in Chrome.
- **Showroom home page.** The live components show many of the new ones at work: a stat with a sparkline, a donut chart, a split button, a toggle button and a toolbar, a page browser with a tree view and a splitter, a file upload, service status with an uptime bar, a calendar and a swatch picker. The toasts there now show the toast as it is drawn today.
- **Pop-ups and dialogs.** A press outside, or Escape, closes only what's open on top. With a popover open inside a modal, the first Escape or a press on the scrim closes the popover, and the next one the modal; a dropdown inside a popover closes before the popover. Both used to close at once.
- **Select, combobox and date picker.** Escape closes their open list or calendar wherever focus is on the page, when it's the one on top. In Safari, where a click on the select doesn't focus it, Escape used to do nothing. The select's list now closes as soon as a press starts outside it.
- **App bar and header.** When a wider window unfolds the bar and its menu closes, `onExpandedChange` hears `false`. That close used to be silent.
- **Button, toggle button, spinner, tag, chip, split button and list.** A missing name, or a size a button can't take, no longer stops the whole page from drawing. The component draws the nearest thing that works, such as a spinner that says "Loading", and in development the browser's console says what to fix.
- **Alert.** A role given to an alert no longer replaces the one it sets from its tone and from whether it's live.
- **Segmented control, boxed tabs and theme switch.** The bar's edge now counts inside its size, as the design draws it, so there are 2 px between an item and the edge, not 1. The bars keep their heights, and their items are 2 px shorter, and the theme switch 2 px wider.
- **Getting started.** The README, the Docs page and the rules for projects now name the same folders to copy, `assets/`, `css/`, `components/`, `conformance/`, `output/`, `package.json` and `LICENSE`, and the same entry folder, `design-system/`. The Docs page also shows the Tailwind theme and the token files in use.
- **Showroom React code.** Every React snippet the Showroom shows or copies, including the preview's, starts with the import line of the components it uses.

### Fixed

- **Words hidden for screen readers.** The words, and the charts' tables, that only screen readers read no longer stretch a page whose content scrolls inside an area: the page could be scrolled far past its end. Each component now holds them inside its own box, and the charts' tables take no room at all. It touched 18 components, among them the charts, the stepper, the timeline, the nav item and the spinner.
- **Radio.** A disabled radio that is chosen shows its dot again. The dot was the same gray as a light page, so it disappeared.
- **Chip and tag.** The focus ring of the remove button shows on a brand chip or tag. It was red on red. On a brand or inverse chip it takes the chip's own text color, and on a brand tag the inverse focus color.
- **App bar.** With hide on scroll on, a link reached with Tab or a heading jumped to lands below the bar, not under it.
- **Pagination.** It no longer runs off the side of a 320 px phone. In a narrow space the numbers bar shows "6 of 11" between Previous and Next in place of the numbers. The select type's Previous and Next show only their icons there. Markup written by hand adds the "6 of 11" item after Previous.
- **Footer.** On a phone, Tab reaches the columns before the brand, in the order they're seen. Markup written by hand holds the links twice, folded and in columns, with the brand once between them, as the component's does.
- **Select.** An open list inside an open accordion panel shows every choice. The panel used to cut it off. The list now shows over the whole page. It rises into place when it opens above, and a soft shade at its foot says more choices wait below.
- **Footer links among words.** A link written among words in the footer, such as a name in the copyright line, is underlined, so it no longer differs from the words around it by color alone.
- **Footer links that open a new tab.** A column link given `external` is only as wide as the words you see. Its column used to keep room for the hidden words "(opens in a new tab)" in bold, which left a wide gap after it. A nav item's label leaves out any words marked `data-unseen` the same way.
- **App bar.** In a wide bar with no links and too little room, the search field no longer spills its icon and shortcut over the logo. What doesn't fit runs off the end, where the bar folds it into the menu.
- **Sidebar.** A group that holds the current page keeps its item marked when you close it, so the sidebar still shows where you are. A screen reader hears that item as the current one.
- **Charts.** The bar chart, line chart, donut chart and heatmap write their numbers, months and weekdays in English unless `locale` names another language. A page prepared on a server shows the same numbers once its script runs; they used to change to the reader's language, and React reported the page and its script disagreeing. The heatmap's table formats its values like the other charts.
- **File row and file upload.** File sizes are written in English unless `locale` is given, so a prepared page no longer changes them when its script runs.
- **Read-only upload.** A file upload that is read-only, or one inside a read-only field, takes no files and shows its files without their buttons. It used to accept files anyway.
- **Progress bar.** With `showValue`, the bar shows the value in words when `aria-valuetext` gives them, as the meter does. It used to show a percentage every time.
- **Capacity meter and progress ring.** A page's own attributes can no longer replace the component's role or values by accident.
- **Footer.** A newsletter sign-up in the footer is on the page once, so its label always points at the email field you see, on a phone too.
- **Page header.** An action given after the third goes behind More actions; it used to disappear. Breadcrumbs given as your own links are drawn as they are.
- **Avatar.** When a picture fails to load, the avatar shows the person's initials, or its icon, where a broken image used to show. Avatar groups, avatars with a name and picture tiles do the same.
- **Card.** A component of your own that draws a card body is no longer wrapped in a second body once it's marked as one (`cardPart = 'body'`).
- **Modal and drawer.** A click on the panel itself, its padding or edge included, no longer closes it, and neither does a drag that starts on the panel and ends on the scrim. Only a click on the scrim closes it.
- **Command palette.** While it's open over the page, the page behind stays still. When it closes, it fades out in place like the modal; it used to disappear at once.
- **Select.** The `open` setting works. It holds the list open, for example in a test or a picture of the page, and the new `onOpenChange` reports each request to open or close it.
- **Accordion.** A disabled item stays shut when a screen reader or the keyboard presses it, not only the mouse.
- **Popover and command palette pages.** A paragraph that showed twice, with stray marks around it, shows once.
- **Showroom.** The button page shows its Sizes section, and any section a component's page adds to the usual ones now shows. The Copy button in each code block example copies its code.
- **Numbers that count.** The toolbar's words, a section heading's summary, a file row's size, a log's note and a capacity meter's words take equal-width digits. A number that changes in place, such as "Updated 12 s ago" or "1.1 of 2.4 MB" while a file uploads, no longer moves the words after it.

### Removed

- **Table drag handle.** The table no longer draws a drag handle, because its rows can't be reordered yet. The handle will come back once rows can be moved, with the keyboard as well as the pointer.
- **Package commands.** `release:bundle` is no longer in the package, nor are the commands that test the design system itself (`tokens:prove`, `variants:check` and `conformance:prove`). Build what a site needs with `npm run css:bundle`.
- **Release bundle.** It no longer holds the files the design system tests itself with. Each component's `fixture.tsx` is gone from it, with the helpers beside them and the proofs of the variant helper and the checker. No site reads them, so a site built from the bundle comes out the same.

### What breaks

- **Number field.** An emptied field now reports `null` to `onChange`, where it reported `NaN`. It takes `null` for empty too. Check for `null` in your handler, and pass `null` rather than `NaN` to show an empty field.
- **Status colors.** The badge, tag, avatar and checkbox take `tone` where they took `type` (badge), `scheme` (tag and avatar) and `variant` (checkbox). The old props and their classes are gone: use `tone` and `smbk-<block>--tone-<value>`. The values move with them: the badge's `sunken` is `default`, the tag's `positive` and `negative` are `success` and `danger`, and the avatar's `neutral` is `default` and its old `default`, the dark fill, is `inverse`.
- **Sizes.** The `default` and `small` sizes of the input, search field, select, checkbox, radio and chip are gone, and so is the progress bar's `compact`, as props and as classes such as `smbk-input--size-small`. Use `md` for `default` and `sm` for `small` and `compact`, as `smbk-<block>--size-md` and `--size-sm`.
- **Names for values.** The footer's `look="default"` is `columns`, the label's `type="mono"` is `small`, and the button group's `type="merged"` is `segmented`. Their classes, `smbk-footer--look-default`, `smbk-label--type-mono` and `smbk-btn-group--type-merged`, go the same way. For a main action with a menu, use the split button.
- **Link.** The `underline` flag and `smbk-link--underline` are gone. Every link is underlined; set `standalone` on one that stands on its own.
- **Badge.** The dot look, `look="dot"` and `smbk-badge--look-dot`, is gone. Use the status dot, which shows its words beside it.
- **Card.** The `media` prop and its classes, `smbk-card--media-none`, `-top`, `-side` and `-background`, are gone. Use `layout`: `stacked` for `none` and `top`, `side` for `side`, `behind` for `background`. A card shows no picture unless it is given one.
- **Theme switch.** Its own part and size classes are gone: `smbk-theme-switch--size-lg`, `-md` and `-sm`, and `smbk-theme-switch__indicator`, `__item`, `__control` and `__icon`. Use the segmented control's own: `smbk-segmented--size-lg`, `-md` and `-sm`, and `smbk-segmented__indicator`, `__item`, `__control` and `__icon`. `smbk-theme-switch` stays as the mark of the theme switch.
- **Modal, drawer and command palette.** `onClose` is gone. Use `onOpenChange`, which is told `false` when one asks to close. On the modal and the drawer a leftover `onClose` now reaches the dialog element and gives no warning.
- **Dismissals.** `onDismiss` (alert, banner, toast), `onRemove` (chip, tag) and `onClear` (search field) no longer pass the click's event. They take no argument.
- **Table.** The `draggable` prop is gone. It drew nothing.
- **Design tokens, text styles.** The names by level are gone, in `tokens/`, `output/` and as custom properties. Use the names by size: `h1` to `h6` are `heading-xl`, `heading-lg`, `heading-md`, `heading-sm`, `heading-xs` and `heading-2xs`; `body-l`, `body-m`, `body-s` and `body-t` are `body-lg`, `body-md`, `body-sm` and `body-xs`; `display-1` and `display-2` are `display-xl` and `display-lg`; `label-l`, `label-m` and `label-s` are `label-lg`, `label-md` and `label-sm`. Their bold, light, medium and semibold variants follow, such as `h4-light` to `heading-sm-light`.
- **Design tokens, shadows and colors.** `elevation.0`, `1`, `2` and `3` are `elevation.control`, `raised`, `raised-strong` and `overlay`, and `elevation.inset-2` is `inset-strong`. `color.action.destructive.*` is `color.action.danger.*`. `color.border.edge-highlight` and `edge-highlight-subtle` are `rim` and `rim-subtle`, and `edge-top` and `edge-bottom` are `groove-top` and `groove-bottom`. `color.shadow.s`, `m` and `l` are `sm`, `md` and `lg`. `color.surface.default-disabled` is `color.surface.disabled`, and `color.surface.overlay-subtle` is `color.surface.translucent-subtle`.
- **Design tokens, sizes and widths.** `border-width.default` and `thick` are `border-width.emphasis` and `accent`. `opacity.media.disabled` is `opacity.disabled`. `size.content.480`, `720`, `960` and `1360` are `size.width.480`, `720`, `960` and `1360`, and `size.display.sm`, `md`, `lg` and `xl` are `size.mark.sm`, `md`, `lg` and `xl`.
- **React.** The React components need one more package, `react-aria`, beside `react` and `react-dom`. It brings `react-stately` and `@internationalized/date` with it, which the number field, the calendar and the date picker also use. A site that copies `components/` installs `react-aria` at the version `package.json` names. If the design system's folder sits outside the site's own, its build takes all five packages from the site's own (in Vite, `resolve.dedupe`). Pages written in plain HTML need nothing new.
- **Colors.** `color.surface.overlay` is now the solid surface of panels that open from a control, such as a dropdown's list or a popover. The see-through glass it used to be, for words over a picture, is `color.surface.translucent`, with the same values. A site that used the old name for glass moves to the new one; no component uses it any more.
- **Design tokens.** The raw color ramps in `output/tokens.ts` and `output/tokens.json` are the new ones: `grey`, `red`, `blue`, `green`, `orange` and `yellow`, and the see-through ramps. The frost, moonrise, midnight and steel ramps and the old in-between steps are gone. They never reached CSS; a program that read them from those files reads a semantic color instead.
- **Design tokens.** A program that reads the files in `tokens/` and expects a color as text, such as `"#f9fafb"`, now finds an object. Read its `hex` and its `alpha`, or its `components` and its `alpha`. Or read `output/tokens.json`, which still gives each color as hex text.
- **Table.** The classes of the drag handle's column are gone: `smbk-table__handle`, `smbk-table__header--control`, `smbk-table__cell--control` and `smbk-table__header-name`. Markup written by hand leaves the column out.
- **Font families.** The typography tokens' font family is now a list: the family, its stand-in face, then the system's own font, such as `Geist, "Geist Fallback", system-ui, sans-serif`. In `output/tokens.ts` and `output/tokens.json` it is the same list, written with commas. A program that reads the family as one name takes the first in the list.
- **Colors Figma retired.** They are gone, as custom properties and in `output/`. Instead of `color.action.tertiary.*`, use the same part of `color.action.default.*`. Instead of each action's own disabled colors (`background-disabled`, `foreground-disabled` and `border-disabled` of `default`, `secondary`, `outline`, `ghost` and `inverse`), use `color.action.disabled.background`, `foreground` and `border`. `color.action.default.foreground-hover` is `color.action.default.foreground`, and `color.action.secondary.border` and `border-hover` are `color.border.rim`. `color.text.brand-hover` is `color.text.brand`, `color.text.accent` and `accent-hover` are `color.text.link` and `link-hover`, and `color.text.selected` is `color.text.on-brand`. `color.border.edge-shade` is `color.border.subtle`, `color.feedback.warning.border-subtle` and `info.border-subtle` are the `border` of each, and `color.icon.inverse` is `color.text.inverse`.
- **Sizes and type Figma retired.** `typography.subheading` is gone: use `body-md`. `space.28`, `36`, `80` and `88` are gone: use the step beside each, `space.24` or `32`, `32` or `40`, `72` or `96`, and `96`. `size.display.xs` is `size.8`. In `output/` only, the see-through steps `color.alpha.white.60`, `70` and `80`, `color.alpha.black.70`, `80` and `100`, and `color.alpha.red.20` and `60` are gone, and so are the letter spacings `tighter`, `tight` and `snug`, which are `none`, and `looser` and `caps`, which are `loose`.

### Known gaps

- **Table rows can't be reordered.** The table has no drag handle in this Release, so a site that needs to move rows builds that itself for now.
- **The dropdown has no right-click menu.** It opens from a control on the page, never from a right-click.
- **Some color pairs fall short of contrast.** A few colors measure below the contrast ratio WCAG asks for against the background they sit on. Text needs 4.5 to 1; the edge or mark that shows a control or its state needs 3 to 1. Some pairs are still to be fixed. Others are kept on purpose, a choice of taste for the system's look. The Contrast section of the [color page](https://design.simbolik.ai/foundations/color/#contrast) lists every pair, what it measures and what it needs.

### Take it

The code is on GitHub, https://github.com/simbolik-lab/simbolik-design-system, tagged `v0.2.0-alpha`. On that Release, download `simbolik-0.2.0-alpha.zip`. It holds one `design-system/` folder with what a site builds with and every license, ready to use with no build. The README on GitHub says how to use each part.

A site on 0.1.2 alpha swaps its copy of the bundle for this one, then moves off every name What breaks lists. The conformance checker names each class and custom property the site still uses that is gone; React props it can't see, so search the site's code for the props listed there. A site still on 0.1.1 alpha or earlier reads the [0.1.2 alpha notes](https://design.simbolik.ai/releases/0.1.2-alpha/) too.

The Figma file the design is drawn in is on Figma Community, https://www.figma.com/community/file/1688324308358870630, where anyone can open it and copy it.

The code is under the MIT License and the Figma file under CC BY 4.0. The [Licenses page](https://design.simbolik.ai/licenses/) says what each one asks.

## 0.1.2 alpha · 2026-10-05

Version `0.1.2-alpha`, a small step after 0.1.1 alpha, much of it for phones. A tapped control no longer keeps its mouse-over look or flashes the browser's gray box. The app bar can slide away as the reader scrolls, and the browser's own bar can take the page's color. A site can draw its own logo, and the footer can open a link in a new tab. The conformance checker gains a rule that finds mouse-over looks a phone would keep. What breaks says what to change.

### New

- **Logo and sidebar**: a site can draw its own logo. Give your logo's shapes to the logo as `shapes`, or to the sidebar as `logoShapes`. They take the same form as the built-in logo: a name, the frame, the view boxes of the mark and the wordmark, and their paths. Your logo is drawn and colored like the built-in one.
- **App bar**: on a phone, the bar can slide away as the reader scrolls down and come back as soon as they scroll up. Turn it on page by page with `hide-on-scroll`. It stays at the top of the window and never hides while a menu is open or keyboard focus is in it. For a reader who asks for reduced motion, it hides and shows at once. Wide screens keep the bar as it is.
- **Footer**: give a column link or a social icon `external` and it opens in a new tab. A screen reader says "(opens in a new tab)" after its name; nothing changes on screen. Legal links always stay in the same tab.
- **Theme switch**: `followThemeColor()` colors a phone browser's own bar to match the page, and keeps it matching when the theme changes. Call it once where the page sets its theme. Without it, a dark page can sit under a white bar.

### Changed

- **Checker**: a new rule, sticky-hover, finds a mouse-over look that a phone would keep after a tap. That is a `:hover` rule outside `@media (hover: hover)`. Rules inside a block that asks about hover are fine, and so is `:not(:hover)`.
- **Checker**: each exception in `conformance-exceptions.json` is now printed once, with how many findings it explains and the first 3 places. A long reason no longer fills the report. Add `--explained` to list every finding, as before.

### Fixed

- **Components**: on a phone, a tapped control no longer keeps its mouse-over look until the next tap. Mouse-over looks now wait for a device that can hover. With a mouse, nothing changes.
- **Components**: a tap on a control now shows only the control's own looks. The browser's gray box is gone, and tapping twice quickly no longer zooms the page. Holding a finger on a button, chip or tab no longer selects its label.

### What breaks

- **Checker**: a project's `:hover` rule outside `@media (hover: hover)` now fails its check. Move it inside, splitting off any other state it shares a selector with.
- **Logo and sidebar**: the logo now has one built-in brand, simbolik. Its `brand`, and the sidebar's, take only `simbolik`; the other brand's value and its modifier class are gone. A site that drew that logo passes its own shapes instead: `shapes` on the logo, `logoShapes` on the sidebar.

### Known gaps

- **The app bar has no in-between form.** Wide, it holds its links, search and actions in one row; narrow, it moves them into a menu. On a screen wide enough for the wide form but too narrow for everything in it, they run out of the bar. Until the app bar has a form for this, put `data-layout="narrow"` on a wrapper around a crowded bar.
- **The dropdown always opens downward.** With too little room below its opener, part of the panel ends up out of view. The select's list already opens upward when there's more room above, and the dropdown's panel doesn't yet.
- **Some color pairs fall short of contrast.** A few colors measure below the contrast ratio WCAG asks for against the background they sit on. Text needs 4.5 to 1; the edge or mark that shows a control or its state needs 3 to 1. Some pairs are still to be fixed. Others are kept on purpose, a choice of taste for the system's look. The Contrast section of the [color page](https://design.simbolik.ai/foundations/color/#contrast) lists every pair, what it measures and what it needs.

### Take it

The code is on GitHub, https://github.com/simbolik-lab/simbolik-design-system, tagged `v0.1.2-alpha`. Clone it, then `npm ci`, `npm run css:bundle` and `npm run release:bundle` write a Release bundle to `release/0.1.2-alpha/`. It's one folder with what a site builds with and every license, and the README says how to use each part.

A site on 0.1.1 alpha swaps its copy of the bundle for this one. Its markup stays as it is, unless it draws the logo's other brand. If it runs the conformance checker, read What breaks first. The new rule can find mouse-over looks in the site's own stylesheets to move. A site still on 0.1 alpha reads the [0.1.1 alpha notes](https://design.simbolik.ai/releases/0.1.1-alpha/) too.

The Figma file the design is drawn in is on Figma Community, https://www.figma.com/community/file/1688324308358870630, where anyone can open it and copy it.

The code is under the MIT License and the Figma file under CC BY 4.0. The [Licenses page](https://design.simbolik.ai/licenses/) says what each one asks.

## 0.1.1 alpha · 2026-10-04

Version `0.1.1-alpha`, a small step after 0.1 alpha. Screen readers get names they were missing, Safari gets two fixes, and a page can load every font from one stylesheet. The segmented control and the badge now match the Figma file, and the conformance checker reads more of a project. What breaks says what to change.

### New

- **One font stylesheet.** `assets/fonts/fonts.css` holds every weight of Funnel Display, Geist and Geist Mono that the design system uses. Link it, and a page waits for one font stylesheet where it waited for fifteen, one per font and weight. The fifteen are still there, so pages that link them keep working.
- **Footer.** A link given `active` tells screen readers it's the current page. A column link also shows it with the navigation item's current look; a legal link looks as it did. `navLabel` names the columns' navigation ("Footer" unless you give another), for a page with two footers.
- **Header.** `navLabel` names the navigation holding its links ("Main" unless you give another), as the app bar's already could.
- **Code block.** `status` says what the last action did, such as "Copied", in a status line the page doesn't show (`smbk-code__status`) and screen readers read out. Empty it after a moment, so the same result is read again the next time.

### Changed

- **Code block.** A bare block shows no bar, but a `label` given to it now names its code when the code scrolls. Before, every bare block was named "Code".
- **Segmented control.** The chosen item is now on the raised surface, a shade lighter than before, like the chosen tab and the chosen theme in the theme switch. Its edge and shadow are the same.
- **Badge.** A badge of the default type now has a thin highlight edge round it, as the Figma file draws it. Its size doesn't change, and the dot look stays as it was.
- **Design tokens.** The token files no longer hold Figma's code syntax (`$extensions.figma.codeSyntax`), the name Figma's Dev Mode shows for a variable. Every custom property is still named from its token's path, so the CSS, TypeScript and JSON outputs are the same.
- **Conformance checker.** The README now says which settings the checker reads from a project's `package.json`. An exception naming a rule the checker no longer has gets a note on every run. It used to stop the check.

### Fixed

- **Sidebar.** Its panel has a name now, the sidebar's `label`, as its navigation had. A page with another side column no longer has two that sound the same to a screen reader.
- **Search field.** In Safari, Escape now empties a field holding text, as other browsers already did, and the page hears it as a change. In an empty field, Escape is left to the page (to close a dialog, say).
- **Select.** Safari no longer cuts the tails off letters such as g, p and y in the value and the choices. The select also points assistive technology at its list only while the list is open, as ARIA 1.2 asks.
- **Table.** The drag handles' column has a heading screen readers read, "Reorder", written out of sight (`smbk-table__header-name`). A name given only as an `aria-label` wasn't read everywhere.
- **Table of contents.** With `extra`, its `aria-label` went to the box around it. It now names the navigation, with or without `extra`, and the heading stays as it is.

### What breaks

- **Conformance checker, the folders it reads.** It used to skip two more folder names at a project's top. Now it skips `node_modules`, dot folders, and `site`, `dist`, `public` and `design-system` at the top, and reads the rest. If a project keeps notes or drafts it shouldn't check, list their folders under `ignore` in its `package.json`, as in `"simbolik": { "ignore": ["notes"] }`.
- **Conformance checker, the `old-system` rule.** The rule is gone, and so are its counts at the end of the report and `oldClasses` and `oldProperties` in the `--json` summary. A class it found is now a class without the project prefix (`class-prefix`). Rebuild it with a component or a Project Piece, or list it under `allowClasses` if the project needs it as it is. An exception naming `old-system` no longer explains anything; remove it.

### Known gaps

- **The app bar has no in-between form.** Wide, it holds its links, search and actions in one row; narrow, it moves them into a menu. On a screen wide enough for the wide form but too narrow for everything in it, they run out of the bar. Until the app bar has a form for this, put `data-layout="narrow"` on a wrapper around a crowded bar.
- **The dropdown always opens downward.** With too little room below its opener, part of the panel ends up out of view. The select's list already opens upward when there's more room above, and the dropdown's panel doesn't yet.
- **Some color pairs fall short of contrast.** A few colors measure below the contrast ratio WCAG asks for against the background they sit on. Text needs 4.5 to 1; the edge or mark that shows a control or its state needs 3 to 1. Some pairs are still to be fixed. Others are kept on purpose, a choice of taste for the system's look. The Contrast section of the [color page](https://design.simbolik.ai/foundations/color/#contrast) lists every pair, what it measures and what it needs.

### Take it

The code is on GitHub, https://github.com/simbolik-lab/simbolik-design-system, tagged `v0.1.1-alpha`. Clone it, then `npm ci`, `npm run css:bundle` and `npm run release:bundle` write a Release bundle to `release/0.1.1-alpha/`. It's one folder with what a site builds with and every license, and the README says how to use each part.

A site on 0.1 alpha swaps its copy of the bundle for this one, and its markup stays as it is. If it runs the conformance checker, read What breaks first. To load the fonts from the one stylesheet, link `assets/fonts/fonts.css` in place of the fifteen.

The Figma file the design is drawn in is on Figma Community, https://www.figma.com/community/file/1688324308358870630, where anyone can open it and copy it.

The code is under the MIT License and the Figma file under CC BY 4.0. The [Licenses page](https://design.simbolik.ai/licenses/) says what each one asks.

## 0.1 alpha · 2026-10-04

Version `0.1.0-alpha`, the first Release of the design system.

### What's in it

- **Design tokens** in the format of the W3C Design Tokens Community Group (DTCG), drawn from the Figma file. The build turns them into CSS custom properties, a Tailwind theme, a TypeScript module and JSON. Two themes (light and dark), two densities (comfortable and compact), and type sizes that follow the window's width.
- **Foundations**: a page for each token group, from color and type to motion, on what the group is for and how to use it.
- **Components**: buttons, inputs, selects, checkboxes and sliders; cards, alerts, toasts and tooltips; breadcrumbs, tabs, a header, a footer and a sidebar that folds into a column of icons; modals, drawers, dropdowns, popovers, tables and a command palette. Each one is a stylesheet first, with a React wrapper over it.
- **One stylesheet**, `css/simbolik.css`, for sites without React, with the fonts (Funnel Display, Geist and Geist Mono) and the Phosphor icons beside it.
- **The conformance checker**, which reads a project and lists every raw value where a design token belongs.

Each component and foundation carries a Status. Most components start as Candidate (believed complete, may still change); the card, the drawer, the logo, the modal and the skeleton start as Experimental (expect big changes). Of the foundations, typography and radius start as Stable; border width, elevation, focus, opacity, size, spacing and stacking order as Candidate; and blur, breakpoints, color and motion as Experimental. From here, each moves on its own.

### What alpha means

Until 1.0, any version can rename or remove things. Its notes list what breaks. The `smbk-` class names are what a site's markup leans on most, so a renamed class is always named in them.

### Known gaps

- **The app bar has no in-between form.** Wide, it holds its links, search and actions in one row; narrow, it moves them into a menu. On a screen wide enough for the wide form but too narrow for everything in it, they run out of the bar. Until the app bar has a form for this, put `data-layout="narrow"` on a wrapper around a crowded bar.
- **The dropdown always opens downward.** With too little room below its opener, part of the panel ends up out of view. The select's list already opens upward when there's more room above, and the dropdown's panel doesn't yet.
- **Some color pairs fall short of contrast.** A few colors measure below the contrast ratio WCAG asks for against the background they sit on. Text needs 4.5 to 1; the edge or mark that shows a control or its state needs 3 to 1. Some pairs are still to be fixed. Others are kept on purpose, a choice of taste for the system's look. The Contrast section of the [color page](https://design.simbolik.ai/foundations/color/#contrast) lists every pair, what it measures and what it needs.

### Take it

The code is on GitHub, https://github.com/simbolik-lab/simbolik-design-system, tagged `v0.1.0-alpha`. Clone it, then `npm ci`, `npm run css:bundle` and `npm run release:bundle` write a Release bundle to `release/0.1.0-alpha/`. It's one folder with what a site builds with and every license, and the README says how to use each part.

The Figma file the design is drawn in is on Figma Community, https://www.figma.com/community/file/1688324308358870630, where anyone can open it and copy it.

The code is under the MIT License and the Figma file under CC BY 4.0. The [Licenses page](https://design.simbolik.ai/licenses/) says what each one asks.
