Diese Seite erscheint auf Englisch und Ukrainisch; unten steht die englische Fassung.
Marking up buttons and fields: data-sa-*
For developers, in code: the data-sa-* attributes that name, group, hint, protect and hide controls — and what the scan does without any of them.
The scan reads what a screen reader reads. Markup is for the things the DOM cannot say: a stable id across re-renders, a name better than a placeholder, an instruction only the author knows, which set a control belongs to, what the assistant must never touch.
The ancestor rule
Most attributes are read with closest(): put one on your component and the control the
library renders inside inherits it. <p-button data-sa-risk="safe"> marks the inner <button>.
The element’s own attribute always wins over an ancestor’s. The exceptions are stated below.
The attributes
| Attribute | Read from | What it does |
|---|---|---|
data-sa-id="email" |
the element | A stable address that survives re-renders. Must be unique: a second element asking for the same id gets a generated one instead. On an <a> it also makes the link a control candidate, and on a section it names a scroll destination. |
data-sa-label="Email" |
the element | The name the assistant uses. Without it the name is derived: <label>, aria-label/aria-labelledby, placeholder, the element’s text. |
data-sa-hint="…" |
the element, else the closest ancestor | An instruction for the assistant, printed beside that control’s name at the moment it decides where to write. The one thing only you know («this field holds every language; the switcher above picks which one you edit»). Write it once, in any language; visitors never see it. |
data-sa-group="Greeting" |
ancestors, up to two names | The set a control belongs to, outermost first (Greeting › Language). Without it: a <fieldset>’s <legend>, a wrapping <label>’s own text, aria-label. |
data-sa-private |
the element or any ancestor | Hidden from reading and acting, the whole subtree. For secrets, tokens and other people’s personal data on your screen. |
data-sa-actions="off" |
the element or any ancestor | Read-only: the assistant may describe the subtree, never act in it. A destructive panel, a reference block. |
data-sa-read |
the element or any ancestor | Opt in a region’s descriptive text (a hint, a form error; up to 400 characters), and — under the marked read mode — the values of the fields inside. Reading the screen. |
data-sa-scroll |
the first match on the page | The container «scroll down» should move, when your body does not scroll. |
The consent attributes — data-sa-risk, data-sa-commit — are on
Consent and commit; the list attributes —
data-sa-list, -row, -field, -add, -fields, -variants, -variant, -variant-of,
-variant-options — on Lists and variants.
What the scan sees without markup
- Every visible form control: inputs, textareas, selects and ARIA comboboxes, checkboxes and radios, buttons, sliders. Password, hidden and file inputs are never scanned.
- Every link, marked or not, with or without an
href— an anchor carrying only a click listener is an ordinary button. A nameless link is dropped; at most 25 are listed, and when that bites, links insidenav,footerandasidego first (the assistant reaches those pages by navigating anyway). Two links sharing a name each carry their destination path so the right one can be picked; atarget="_blank"link is marked, because a popup blocker swallows that click silently. - Destinations for «show me where that is»: a section with
data-sa-idordata-sa-label, anidthat a same-pagehref="#…"points at (the link’s text names it — a table of contents does this work for you), anh1–h6, a named landmark. Capped at 25,h4–h6dropped first. - ARIA state:
aria-expanded(a collapsed disclosure shows as «press to open»),aria-selected/aria-checked/aria-pressed(the selected option of a set),disabledandreadonly.
Names: what to avoid
- A
<label>that wraps a whole group names its controls by the text it writes before them, not by everything inside it. If your label says «Greeting» and then holds a switcher, an input and a hint, the input is named «Greeting» — good — and the switcher’s buttons are named by their own text. - A control with no name is listed as
(unnamed)and is still addressable by id; give it anaria-label: the name is how the assistant tells a row’s tick-box from its text field, and how it tells the visitor which control it changed. - A private descendant does not remove its text from the parent’s name. A button whose text
includes a visitor’s email keeps that email in its name even if you mark the span private; give
the button an
aria-labelinstead. - In Angular, stamp the control’s path (
do.0,persona.role) asdata-sa-id, not itsformControlName, which inside aFormArrayis just the index.
Hints: where to put them
A hint is read from the control it sits on. A hint on a row’s input cannot be read until a
row exists, so the same sentence belongs on the button that creates one. Inside a declared list
row (data-sa-row) a hint is dropped — a list reaches the assistant as one line and its fields
have no entry of their own; put the hint on the list’s own controls outside the rows.
Hints that work are facts about this control, in one sentence: «press this, then press the range; a ready-made range applies at once, calendar dates only on Apply».