Components
Every element in this system renders light DOM and emits the sds-
classes the stylesheet defines. There is no shadow root, no slot and nothing
to theme twice. The element is a shorter, safer way to write markup the
class layer already describes.
The reference pages follow the concerns in the navigation, not the implementation directories. That grouping is for a browse. The index below is alphabetical, because a reader who looks up an element knows its name and not its concern.
Element index#
Alphabetical, because a reader who looks one up knows its name and not its group.
sds-accordion, sds-accordion-itemsds-badgesds-buttonsds-bylinesds-cardsds-checkboxsds-checkbox-groupsds-codesds-confvalsds-decksds-dialogsds-diffsds-embedsds-eyebrowsds-fieldsds-field-errorsds-field-groupsds-filesds-figuresds-footersds-form-errorssds-gridsds-iconsds-icon-tilesds-imagesds-lightboxsds-link<a> with an hrefsds-modalsds-nav-breadcrumbsds-nav-mainsds-nav-pagersds-nav-paginationsds-nav-pillssds-nav-railsds-nav-tocsds-notesds-overlaysds-progresssds-quotesds-slidesds-radiosds-rangesds-searchsds-search-hitssds-search-resultsds-runsds-selectsds-statsds-steps, sds-stepsds-surfacesds-swatchsds-switchsds-tablesds-tabs, sds-tab-itemsds-textareasds-theme| Element | What it is | Reference |
|---|---|---|
sds-accordion, sds-accordion-item |
questions with their answers folded behind them | Navigation — sds-accordion, sds-accordion-item |
sds-badge |
a small, named piece of state | Controls — sds-badge |
sds-button |
the action that starts work, or the press that is a link | Controls — sds-button |
sds-byline |
who wrote it, and when | Content — sds-byline |
sds-card |
a way into something: a chapter, a product, a news entry, a page | Content — sds-card |
sds-checkbox |
one thing that is either so or not | Forms — sds-checkbox |
sds-checkbox-group |
tick any of these, under one question | Forms — sds-checkbox-group |
sds-code |
a fenced block, its head and its copy button | Data — sds-code |
sds-confval |
one configuration value in a reference | Data — sds-confval |
sds-deck |
slides one after the other, at the window's size | Content — sds-deck |
sds-dialog |
a surface that opens over the page, and what opens it | Overlays — sds-dialog |
sds-diff |
a file's changes | Data — sds-diff |
sds-embed |
a document from somewhere else, in a frame this page controls | Media — sds-embed |
sds-eyebrow |
the line over a title, saying what kind of thing it opens | Content — sds-eyebrow |
sds-field |
one line of whatever a reader types | Forms — sds-field |
sds-field-error |
the message under an invalid field | Forms — sds-field-error |
sds-field-group |
fields that answer one question, under one caption | Forms — sds-field-group |
sds-file |
the platform's own picker, with its button painted | Forms — sds-file |
sds-figure |
a picture and the claim it makes | Media — sds-figure |
sds-footer |
how a page ends, and where the rest of the site is | Navigation — sds-footer |
sds-form-errors |
what stopped the form, at the top of it | Forms — sds-form-errors |
sds-grid |
the wall a reader reads a set in | Content — sds-grid |
sds-icon |
one icon from the set, in the document rather than linked | Controls — sds-icon |
sds-icon-tile |
one glyph in a wall of them, scanned rather than read | Content — sds-icon-tile |
sds-image |
a picture, and nothing around it | Media — sds-image |
sds-lightbox |
a drawing open at the size of its drawing | Media — sds-lightbox |
sds-link |
a link, and always an <a> with an href |
Controls — sds-link |
sds-modal |
the surface alone, with nothing that opens or closes it | Overlays — sds-modal |
sds-nav-breadcrumb |
where the page sits, as a trail | Navigation — sds-nav-breadcrumb |
sds-nav-main |
the bar at the top of a page | Navigation — sds-nav-main |
sds-nav-pager |
the way on from a page in a sequence | Navigation — sds-nav-pager |
sds-nav-pagination |
where a list continues | Navigation — sds-nav-pagination |
sds-nav-pills |
navigation for the sections of a page | Navigation — sds-nav-pills |
sds-nav-rail |
the navigation rail beside a column | Navigation — sds-nav-rail |
sds-nav-toc |
what is on this page, and where in it the reader is | Navigation — sds-nav-toc |
sds-note |
what an answer carries besides the answer | Content — sds-note |
sds-overlay |
the wash a floating surface sits on | Overlays — sds-overlay |
sds-progress |
how far a running job has got | Controls — sds-progress |
sds-quote |
a sentence borrowed from somewhere, with where it came from | Content — sds-quote |
sds-slide |
one 16:9 frame of a deck, the page at twice the size | Content — sds-slide |
sds-radio |
one answer out of a few, all of them visible | Forms — sds-radio |
sds-range |
a value picked along a run of them | Forms — sds-range |
sds-search |
the search for a page in a site with no server | Navigation — sds-search |
sds-search-hits |
the answer to a query | Navigation — sds-search-hits |
sds-search-result |
one hit in a list of them | Navigation — sds-search-result |
sds-run |
work in progress, as its stops | Controls — sds-run |
sds-select |
one answer out of a list the reader does not need to see | Forms — sds-select |
sds-stat |
a number stated as a fact | Content — sds-stat |
sds-steps, sds-step |
an instruction read from the top, numbered down one rail | Content — sds-steps, sds-step |
sds-surface |
a filled plane holding a statement | Content — sds-surface |
sds-swatch |
one colour, as the chip, the name and what it resolves to | Content — sds-swatch |
sds-switch |
a setting that takes effect where it stands | Forms — sds-switch |
sds-table |
rows and columns, with the scroll a wide one needs | Data — sds-table |
sds-tabs, sds-tab-item |
one set of panels, one of them shown | Navigation — sds-tabs, sds-tab-item |
sds-textarea |
an answer of more than one line | Forms — sds-textarea |
sds-theme |
the mode the page is in, as one press that changes it | Controls — sds-theme |
What box an element is#
Each component's own stylesheet states this, in a @layer base block
above the one that draws it: the flow contract, whose three rules
How the stylesheets are written explains. A contract split across a shared list
and a component file drifts into two layers.
Every element is the box it draws. A custom element is inline until
told otherwise. An inline tag around a block makes itself the box a row lays
out, while the block sits inside it. Gap, alignment and margin then all land
one level too high. So the stylesheet states a display for every element,
and the class it draws states the same one. Where no script runs, only the
class remains, and the page measures the same either way.
An element in a flow is a block and carries the step below it. That is why what it draws inside gives that step up. An element in a line of text or a row of controls is inline. Either way a reader reads a distance off the element it belongs to, not off two of them. No rule in this system reaches past a tag to find a block.
sds-dialog, sds-lightbox, sds-modal, sds-overlay and
sds-deck are display: contents. What they draw is in the top layer or
fixed to the viewport, so a box where they stand is one nothing fills. A
deck of its own draws its poster, and the poster is its own box. That is
the whole list, and each states it.
What a component is made of#
Everything a component is, it is through a property of its own. A set
at the top of its stylesheet that every declaration below reads. So a
variant assigns values and draws nothing, and a surface that needs one
instance different sets a property instead of a new class. The shape, its
reasons and the nesting rules are How the stylesheets are written. The
consequence matters here: an ancestor can re-theme any single instance
through its --sds-<name>-* properties, and through nothing else.
Addressed, never rebuilt#
Everything that fits in a string is a property. Between the tags goes only what an attribute cannot carry, and that is content, never structure. The paragraphs of a summary, the blocks behind a question, the picture a renderer already wrote.
<!-- Addressed. -->
<sds-card heading="Release 1.4" tag="news" label="12 May" href="/news/1-4">
<p>What changed, in the two lines that decide whether it is opened.</p>
</sds-card>
<!-- Rebuilt. This is the failure the system exists to prevent. -->
<article class="sds-card">
<div class="sds-card__body">…</div>
</article><!-- Addressed. -->
<sds-card heading="Release 1.4" tag="news" label="12 May" href="/news/1-4">
<p>What changed, in the two lines that decide whether it is opened.</p>
</sds-card>
<!-- Rebuilt. This is the failure the system exists to prevent. -->
<article class="sds-card">
<div class="sds-card__body">…</div>
</article>
A sds-x__y class is sds-x's own name for its own node. A page can
write .sds-card and .sds-note--warn. It must not write
.sds-card__foot: the day that node changes, every hand-written copy is a
surface nobody fixes.
If an element cannot say something a page needs, close the gap in the element. A consumer who writes three declarations into their own stylesheet is the outcome this system exists to prevent; see Design system.
If an element cannot say something a page needs, close the gap in the element. A consumer who writes three declarations into their own stylesheet is the outcome this system exists to prevent; see Design system.
Properties and attributes#
Strings, numbers and booleans are attributes, and a server writes them. A list or a piece of markup is a property, set from JavaScript or from a template that binds one:
<sds-table density="compact" scrollable
.columns="${[{ head: 'Tool' }, { head: 'Answers', cls: 'sds-td-meta' }]}"
.rows="${[{ cells: ['search', 'yes'] }]}"></sds-table><sds-table density="compact" scrollable
.columns="${[{ head: 'Tool' }, { head: 'Answers', cls: 'sds-td-meta' }]}"
.rows="${[{ cells: ['search', 'yes'] }]}"></sds-table>
A renderer that holds markup, not data, has the other route: write the markup between the tags and let the element take it. That is how the Guides theme emits a code block with its colour and a rail with its links resolved. And a figure whose picture is on the page before a script runs.
Where a property's name is more than one word, its attribute has its own spelling:
iconOnlyicon-onlysds-buttonlangcode-langsds-codeboxStylebox-stylesds-surfacefieldIdfield-idsds-fieldminWidthmin-widthsds-fieldperPageper-pagesds-nav-paginationpreviousHref, previousLabel, nextHref, nextLabelprevious-href, previous-label, next-href, next-labelsds-nav-pager| Property | Attribute | On |
|---|---|---|
iconOnly |
icon-only |
sds-button |
lang |
code-lang |
sds-code |
boxStyle |
box-style |
sds-surface |
fieldId |
field-id |
sds-field |
minWidth |
min-width |
sds-field |
perPage |
per-page |
sds-nav-pagination |
previousHref, previousLabel, nextHref, nextLabel |
previous-href, previous-label, next-href, next-label |
sds-nav-pager |
box-style carries layout for the plane itself, the box that draws the
frame. A style on the element sizes the block around it instead. The
two are different boxes, and the property says which one you mean.
box-style carries layout for the plane itself, the box that draws the
frame. A style on the element sizes the block around it instead. The
two are different boxes, and the property says which one you mean.
Names that had to differ#
Each of these is a global HTML or ARIA attribute a component must not override.
headingtitletitle is the global attribute, and puts a tooltip on the whole
componentasrolerole is the ARIA attribute, so role="maintainer" claims a role
that does not exist, and axe says socode-langlanglang names the human language, so lang="json" sends every
screen reader to a language tag that does not exist| Written | Instead of | Because |
|---|---|---|
heading |
title |
title is the global attribute, and puts a tooltip on the whole
component |
as |
role |
role is the ARIA attribute, so role="maintainer" claims a role
that does not exist, and axe says so |
code-lang |
lang |
lang names the human language, so lang="json" sends every
screen reader to a language tag that does not exist |
What an element announces#
Every event below bubbles and crosses roots, so a page listens on the element, not on what is inside it.
detailsds-changesds-nav-pills, sds-nav-main, sds-nav-rail, sds-tabs{ index, label }, the item that became currentsds-changesds-nav-pagination{ page }, one-based. Cancelable: call preventDefault() to
page in place and not follow the linksds-changesds-checkbox, sds-switch, sds-radio,
sds-checkbox-group, sds-select, sds-filesds-inputsds-field, sds-textarea, sds-rangesds-commandsds-button with for{ command, source }, sent to the element named by for,
the way the platform's own invokers do itsds-note-actionsds-note with actionhref announces nothing: the link is
the answersds-dialog-confirmsds-dialog with confirm-labelsds-dialog-cancelsds-dialogclose()sds-slide-opensds-slide with zoomablesds-theme-changesds-theme{ theme }: "light", "dark", or null for the machine's| Event | From | detail |
|---|---|---|
sds-change |
sds-nav-pills, sds-nav-main, sds-nav-rail, sds-tabs |
{ index, label }, the item that became current |
sds-change |
sds-nav-pagination |
{ page }, one-based. Cancelable: call preventDefault() to
page in place and not follow the link |
sds-change |
sds-checkbox, sds-switch, sds-radio,
sds-checkbox-group, sds-select, sds-file |
the new state, the chosen value, the values ticked, or the files chosen |
sds-input |
sds-field, sds-textarea, sds-range |
what is in the field, or where the thumb now stands |
sds-command |
sds-button with for |
{ command, source }, sent to the element named by for,
the way the platform's own invokers do it |
sds-note-action |
sds-note with action |
the label pressed. A note with href announces nothing: the link is
the answer |
sds-dialog-confirm |
sds-dialog with confirm-label |
none. The press is the whole message |
sds-dialog-cancel |
sds-dialog |
none. Anything that closed a dialog without a confirm: the cancel
button, the header X, Escape, a close() |
sds-slide-open |
sds-slide with zoomable |
none. The deck that runs through the slide opens at it |
sds-theme-change |
sds-theme |
{ theme }: "light", "dark", or null for the machine's |
One control wires to another in markup:
<sds-button for="the-drawing">Open the drawing</sds-button>
<sds-lightbox id="the-drawing" src="/art/pipeline.svg" alt="…"></sds-lightbox><sds-button for="the-drawing">Open the drawing</sds-button>
<sds-lightbox id="the-drawing" src="/art/pipeline.svg" alt="…"></sds-lightbox>
An id and an event, so neither end holds the other. command says what
the press asks for: show unless written otherwise, and close or
toggle where that is what the press means.
Before the script, and without one#
These elements survive both. A prerendered page holds its markup already. The element upgrades it in place instead of a second draw, and a reader with no script keeps everything but the behaviour.
Two things follow for anything that renders in Node: the specimen cards, the Guides site, a static export.
- The element lifts the content between the tags on connect, which never
happens outside a browser. The same content arrives as the
contentproperty instead, and every element reads whichever it got. - A card carries no JavaScript, so
renderStaticflattens each element to the markup it renders. An element with children has no flat form; the body goes in as a property there.
Page layout for the page these components stand in, and Screens for finished pages built out of them.
Page layout for the page these components stand in, and Screens for finished pages built out of them.