Skip to content

os-text-field: add hide-label so a compact field can have a name without a visible label - #792

Open
juanlentino wants to merge 1 commit into
WordPress:trunkfrom
juanlentino:feat/os-text-field-hidden-label
Open

os-text-field: add hide-label so a compact field can have a name without a visible label#792
juanlentino wants to merge 1 commit into
WordPress:trunkfrom
juanlentino:feat/os-text-field-hidden-label

Conversation

@juanlentino

Copy link
Copy Markdown
Contributor

Fixes #789.

The problem

label drove both the visible label and the accessible name from one value, so a compact field had two reachable states and neither was right:

  • label omitted → the inner <input> gets aria-label="", i.e. no accessible name
  • label set → the name is correct, and a label renders above a toolbar search with no room for one

placeholder does not close the gap: it is not an accessible name, and it disappears on the first keystroke.

The change

hide-label separates presentation from naming. The <label> is still rendered, still paired with the input by for=, and still the accessible name — it is only taken out of the visual flow, using the same idiom as .os-constellation__row-note in openstation-layout.css.

<os-text-field label="Search notes" hide-label placeholder="Search notes…"></os-text-field>

Hiding it with display: none, or dropping the element and relying on aria-label alone, would have been easier and worse: the first removes it from the accessibility tree, and the second gives up the <label for> association, which is the more robust of the two bindings. Keeping both is the point.

Declared as hideLabel in static props, so Component.observedAttributes kebabs it to hide-label — matching autoGrow, labelPosition and the other multi-word props in the kit.

Call sites

Four first-party search fields adopt it: comments, plugins, trash, my-wordpress. After this, no <os-text-field> under apps/ is unnamed.

A correction to the issue: #789 says seven. That number was measured against a checkout that has since moved; on current trunk it is four. One of the seven I counted was also a false positive — os-number-field's help summary string contains the literal text <os-text-field>, which my scanner read as a call site. It has its own label prop and was never affected. I have not edited the issue body; happy to if you'd prefer the record corrected there.

Tests

Three cases in os-text-field.test.ts:

  1. a labelled field pairs <label for> with the input and names it
  2. hide-label keeps the label, the pairing and the name, and only adds the modifier class
  3. negative controlhide-label without label names nothing, because it is a presentation switch and not a source of names

One honest caveat on verification. I could not run your vitest suite locally: devEngines pins Node to >=24 <25 and this machine is on v26, so npm refuses before install. I validated what I could without the harness — the prop is declared, read as a boolean the same way disabled is, the modifier is applied, aria-label is untouched, the style rule exists and is not display: none, and kebab( 'hideLabel' ) === 'hide-label' against your own kebab() in src/ui/core/component.ts. The vitest cases themselves are unexercised, so please let CI be the judge of those.

Not included

os-textarea and os-number-field have the same coupling. I left them alone rather than widen an accessibility fix into a kit-wide API change without your read on the attribute name first — if hide-label is the shape you want, extending it is mechanical.

`label` drove both the visible label and the accessible name from one
value, so a compact field had two states and neither was right: omit it
and the inner input gets `aria-label=""` (no accessible name), or set it
and a label renders above a toolbar search that has no room for one.
`placeholder` does not close the gap -- it is not an accessible name, and
it disappears on the first keystroke.

`hide-label` splits presentation from naming. The <label> is still
rendered, still paired with the input by `for=`, and still the accessible
name; it is only taken out of the visual flow, using the same idiom as
`.os-constellation__row-note` in openstation-layout.css. Hiding it with
`display: none` -- or dropping the element -- would take it out of the
accessibility tree too, which is the opposite of the point.

Four first-party search fields adopt it: comments, plugins, trash and
my-wordpress. After this, no `<os-text-field>` under apps/ is unnamed.

Fixes WordPress#789
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

os-text-field: no way to expose an accessible name without rendering a visible label — four first-party search fields ship unnamed

1 participant