ADR-037: Native Form Controls Site Wide
Status
Accepted (2026-10-27). Checked against the merged code: lwc/nativeControls/nativeControls.css, config/jest.config.js, and the .html of apiTester, coverLetterGenerator, resumeBuilder and codeViewer.
Context
Salesforce’s base components (lightning-input, lightning-combobox, lightning-textarea, lightning-button) draw at 32 px. The site’s own controls are 44 px, the touch target the site holds itself to. Where the two sat in one row, the row did not line up. The alignment audit of 2026-10-27 measured offsets of up to 46 px, and the API Lab’s parameter grid was the worst case. The contact and testimonial forms already used native controls and measured clean.
The site also had two native looks, not one. The contact forms and the API Lab’s parameter grid differ in fill, edge and focus colour. Several streams copying one of them would have made a third.
Decision
Replace the base form components outright with native controls, styled by one shared CSS only module, c/nativeControls.
- One module. A component adds
@import "c/nativeControls";at the top of its CSS and uses the classesnc-control,nc-button,nc-field,nc-label,nc-hint,nc-errorandnc-required. The module sets the height (44 px), the fill, the edge and the focus ring from the--pf-tokens, so a control follows the visitor’s theme. A component’s own CSS may set layout (width, grid, gaps) and never a control’s height, colours, edge or focus. - 11 controls moved, counted from the base component tags in the four components’ markup before and after: the API Lab’s endpoint combobox, Advanced query text, token Email and Purpose, and the grid’s own inputs and selects now use
nc-control. The AI Lab’s Company Name, Job Title and job description. The resume’s “Tailor for” combobox and its Download PDF and Copy ATS text buttons. The code viewer’s copy button. - Kept from the base components. A visible label tied to its control by
forandid. A required mark (requiredon the control and anaria-hiddenasterisk in the label). The email check witharia-invalidandaria-describedby, announced to screen readers. Keyboard use and a visible focus ring.color-schemecomes from a--pf-color-schemetoken (light or dark) that the theme layout and the site’sstyles.cssset in all three theme blocks, so a nativeselectand its menu follow the theme. - Left as they are. The resume’s two checkboxes stayed as
lightning-inputwhen this was accepted (moved on 2026-10-30, see the amendment below).lightning-card,lightning-spinnerandlightning-iconstay where they are used. The contact and testimonial forms are not moved. They already measure clean.
Alternatives considered
| Option | Why not |
|---|---|
| Keep the base components and restyle them | Their height is drawn inside the component, which the site’s CSS does not reach, so the 44 px target could not be set from outside. [unverified] against each component’s current styling hooks. |
| Each component styles its own native controls | Two native looks already existed. A third copy is how the site got two. |
Implications
- One look everywhere. A change to the module changes every replaced control, and there are no styling hooks to maintain.
- WebKit draws a native
selectat 48 px where Chromium draws 44. The alignment audit flags a row that pairs a select with a button in WebKit. The documents components have no such row (alignment audit, 2026-10-27). - A CSS only module needs a Jest mapping.
config/jest.config.jsmapsc/nativeControlsto its CSS file. A second CSS only module needs its own line. - A script that finds a field by its old name misses it. An AI Lab field’s accessible name no longer carries “(required)”, so a lookup by that text finds nothing.
- Not measured on every device. The look was checked in Chromium and WebKit on the integration site. A real phone is my check.
Amendment (2026-10-30): the resume’s checkboxes are native
The resume’s two include toggles are now native input type="checkbox" elements inside a wrapping label with a visible focus ring (.toggle-input:focus-visible), in place of lightning-input. The reason is weight, not alignment. lightning-input carried about 240 KB uncompressed of component machinery into the resume view for two checkboxes (performance audit, 2026-10-29).
- The count changes. The 11 controls counted above were base component tags. The two checkboxes bring the total moved to 13. The count of 11 stays true for the date it was made.
lightning-formatted-date-timeis gone as well.c-view-sourceformats its fetch time withIntl.DateTimeFormatin atimeelement, so the site uses that base component nowhere.lightning-card,lightning-spinnerandlightning-iconremain, and removing the platform stylesheets they depend on was tried and not shipped (Technical Guide §2.11).- The checkbox look is the browser’s. I did not check it on a real phone. That is my check.