Data display
Tag
An arbitrary label started by the user. It can be removed — and that is the main difference from a badge, which has five values from the library's vocabulary and cannot be removed.
Markup
<span class="inst-tag">worldgen<button class="inst-tag-remove" type="button" aria-label="Remove the worldgen label"></button></span>
<span class="inst-tag">nightly<button class="inst-tag-remove" type="button" aria-label="Remove the nightly label"></button></span>
<span class="inst-tag">priority:high</span>
Contract
| What | Required | Why |
|---|---|---|
A real <button> for removal |
yes | A cross as text cannot be pressed from the keyboard and there is nothing to speak |
An aria-label with the word of the label |
yes | "Remove the worldgen label" rather than "Remove": a row of ten "Remove"s is indistinguishable by ear |
| Moving the focus after a removal | yes, in the application | A vanished element takes the focus nowhere |
| The removal button | no | It is added only where removal is possible |
Accessibility
| The removal button | A real <button> rather than a cross as text: it has to be pressable from the keyboard and speakable |
| The name of the button | An aria-label with the word of the label: "Remove the worldgen label" rather than "Remove". A row of ten "Remove" buttons is indistinguishable by ear |
| The focus after a removal | It goes nowhere if the element has vanished. The application has to move it to the next tag or to the container |
| The tap target | The glyph is --size-chevron, that is 10px. This is below the 24px of WCAG 2.5.8: the tap area is widened by a pseudo-element while the glyph itself stays small |
| Tone | A tag has none, so the question of "colour as the only carrier" does not arise |
Variants
Without a removal button
Markup
<span class="inst-tag">read-only</span>
<span class="inst-tag">priority:high</span>
The button is added only where removal is really possible. A cross that does nothing is worse than no cross.
JS
Include the module once per page — there is no need to initialise the
components one by one, instrument.js works by delegation and sees nodes that
arrived later.
<script type="module" src="instrument.js"></script>
What instrument.js does
The example in the header is live: press the cross — the tag is removed and the focus goes to its neighbour.
A press on .inst-tag-remove removes the tag and moves the focus to the
neighbouring cross — otherwise a deleted element takes the focus nowhere, and
somebody on a keyboard ends up at the start of the document.
Events
inst:remove bubbles from the tag, and its detail is { value }: the
data-value if there is one, otherwise the text of the label.
The event is cancellable, and in a data-driven application cancelling it is the
norm: the markup there is recreated by a re-render rather than by
instrument.js.
list.addEventListener('inst:remove', (e) => {
e.preventDefault(); // the tag will stay in the markup
store.dropTag(e.detail.value); // the re-render will take it away
});
Options
| Attribute | What it does |
|---|---|
data-value |
What arrives in detail instead of the label's text — an identifier rather than a human name |
API
| Name | What it does |
|---|---|
| class | |
inst-tag | The label |
inst-tag-remove | The removal button. A real <button>; the removal is carried out by [instrument.js](../../foundations/behavior.md) |
| Name | Value | What it does |
|---|---|---|
| attribute | ||
data-value | — | On .inst-tag. What arrives in the detail of inst:remove instead of the label's text |
| Name | Value | Where from |
|---|---|---|
| token | ||
--control-h-sm | 24px | base +14: density · scale |
--radius-sm | 6px | base +4: scale |
--text-xs | 0.78125rem | base +4: scale |
--space-2 | 4px | one across every cell |
--space-3 | 6px | one across every cell |
--surface-recessed | light-dark(oklch(0 0 0 / 0.060), oklch(1 0 0 / 0.050)) | one across every cell |
--border | light-dark(oklch(0 0 0 / 0.12), oklch(1 0 0 / 0.11)) | one across every cell |
--hairline | 1px | base +1: screen |
--size-chevron | 10px | base +4: scale |
--text-muted | light-dark(var(--n-8), var(--n-6)) | one across every cell |
--err-text | light-dark(var(--err-5), var(--err-3)) | base +1: theme |
Why the kit works this way — the constitution · Open source under MIT, github.com/keshon/instrument