Skip to contentWolf-Rayet

Decision records

ADR-0091 Three fields are one field, and the first built component leaves the set

Accepted2026-09-16Phase 4, reopened

#Context

Standing item 24 has been open since ADR-0081 and was narrowed by ADR-0083 and ADR-0089. What remains is the case this repository has never met: input-field, text-area and select are built, and §12 says two components alike in all eight dimensions are one component. They are alike in all eight.

That is not an inference from prose. The six checkable axes read identically out of component.config.json — Emitter, [1, 2, 3], interactive, no vouching, no acknowledgement, no persistence — and so do the two the contracts carry: the same two governed parts, label and hint, with the same roles, and no disclosure (ADR-0083 measured that a closed select's options are never in the frame). Below the identity test the three are closer still:

  • The token entries differ only in prose. With each component's own name

substituted out, text-area's entry is input-field's. select's adds two values, disclosure-color and disclosure-size, both for its chevron.

  • The stylesheets differ by one declaration for text-area —

resize: vertical — and by the chevron's rules for select.

  • The components differ by the native element they render: <input>,

<textarea>, <select>. That is an implementation fact. ADR-0081 refused dropdown because Carbon ships it beside select for exactly that reason, and a rule applied to rows and not to built components would be a rule about the roster's history rather than about the system.

Removing a built component has never been done here. ADR-0077's argument says an audit's conclusion and a removal's consequences belong in different commits, and they are: this record decides, and the commit that follows carries it out.

#Decision

text-area and select leave the set. InputField gains control.

<InputField control="text" … />                      // the default
<InputField control="multiline" rows={4} … />
<InputField control="choice" options={…} placeholder="…" … />

control is how the field is drawn, never what it claims — the same standing §12 gives variants, and for the same reason: it does not appear in the eight dimensions and adding it there would be adding an axis so that an audit could read it. The props are a discriminated union, so rows is only accepted with multiline and options only with choice, and each is refused by the compiler anywhere else.

What select carried moves with the control, not into the component's identity. ADR-0028's set rule — *exactly one of the set may be chosen* — and its carrier, the chevron and the filled note are declared in the contract under controls.choice. input-field gains the two chevron tokens. The chevron's ADR-0028 ownership moves from select/disclosure to input-field/choice, drawn identically, which react:test already asserts.

The scenes stay and are renamed. 36-text-area-calm becomes 36-input-field-multiline-calm and 37-select-calm becomes 37-input-field-choice-calm, composed from InputField by their generators. Both baselines rename the keys on both platforms and move no value. That is the claim this record stakes: the collapse lost nothing a reader can see, and a baseline gated at exact equality is the instrument that can say so. If linux-x64 reports a single BASELINE MOVED on either scene, the claim is false and this record is wrong.

No deprecation period. §12 promises one, with notice and codemods, for a published API. Every package is private at 0.0.0 (§13, amended this pass), so there is no consumer to give notice to. The Carbon slugs text-area and select map to input-field in ADR-0021's exclusion table, beside the other rows that collapsed into a built component plus a control.

#Found while reading, and fixed with it

The field had no accessible name. InputField's own doc comment says label is *"rendered as a real <label> wired to the control by id"*. It was a <span> with no association, and the control carried aria-describedby for the hint and nothing for the label — in all three components, and in NumberInput, which copied the construction. The label is now a <label> with htmlFor, which is inline exactly as a span is, so no measured value should move for it either; the same gate covers both claims.

#avatar, reviewed on the axes rather than on a record

ADR-0082 refused avatar by citing what ADR-0028 says a shared mark must be, and the handoff named that as the audit conclusion most likely to be wrong, because it argued from a record. Placed on the checkable axes, an avatar is a non-interactive Emitter at [1, 2] that does not vouch — a picture of who a record belongs to is owned data, not an observation — which is the bucket tooltip, empty-state, pagination and code-snippet occupy. Separation would have to come from D4, and an avatar has no governed copy: the person's name and picture are product-supplied, which ADR-0009 exempts, and the picture is a mark, which §12 excludes. Every one of the built set declares at least one governed part; a component with none is exempt content in a frame. With a status beside it, it is presence. The refusal stands, now on a measurement.

#Rejected

  • Keep all three, on the ground that consumers of Carbon and Lightning

expect TextArea and Select. Expectation is provenance, and ADR-0082 recorded that provenance is not a separation. A system that states a refusal rule and exempts its own built components from it has a rule about rows.

  • Keep TextArea and Select as thin aliases of InputField. An alias is

a second name for one component, which is the exact thing the identity test exists to prevent, and it would drift — NumberInput copying the label defect is what copying looks like.

  • Collapse text-area only, keeping select for its set rule. §12's first

step is to extract the rule; the rule extracted, what remains is input-field, as ADR-0050 found for acknowledge.

  • Collapse number-input too. ADR-0089 separated it on D4: it owes a

governed range part the other three do not.

  • A separate multiline boolean and a separate options prop without a

discriminant. Three states expressed as two optional props admit a fourth that means nothing.