Skip to content

fix!: convert Input and TextField BEM classes to flat class names - #5127

Open
millus wants to merge 9 commits into
mainfrom
feat/bem-to-flat-input-textfield
Open

fix!: convert Input and TextField BEM classes to flat class names#5127
millus wants to merge 9 commits into
mainfrom
feat/bem-to-flat-input-textfield

Conversation

@millus

@millus millus commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

Summary

Converts Input and TextField from BEM-style class names to the flat class name convention. Part of #5104. This is the last of three component PRs — see also #5114 (Banner) and #5115 (Field + Switch + Radio + Checkbox). ADR 0006 documenting the convention is in #5134.

Changes

Input — full class name cleanup:

Old New
eds-input-container eds-input (root, renamed to match component)
eds-input control (inner <input>/<textarea> element)
eds-adornment adornment
eds-error-icon error-icon
eds-adornment__adornment item
eds-adornment__text text

All inner element rules are now fully nested inside .eds-input using CSS nesting. Cross-component references in textarea.css, autocomplete.css, and elements.css updated accordingly.

TextField:

  • eds-text-field__headerheader
  • eds-text-field__infoinfo

Adds eds-text-field as the root class on the Field wrapper so inner elements can be properly scoped — consistent with how Radio and Checkbox add their own class to the Field wrapper.

BREAKING CHANGE: Consumers targeting these class names directly in their own CSS must update to the new flat names.

Closes #5104

Test plan

  • npx jest --testPathPatterns="next/Input|next/TextField|next/TextArea|next/Autocomplete" --no-coverage — 133 tests pass
  • Start Storybook and verify:
    • Input: start/end text adornments, start/end icon adornments, disabled and readonly states
    • TextField: label row with info tooltip button, description, helper message, invalid state
    • TextArea: resize handle, char count, error state

millus added 3 commits June 26, 2026 13:15
Renames BEM element classes on the adornment sub-elements to flat names:
- eds-adornment__adornment → item
- eds-adornment__text      → text

Also nests .item and .text inside .eds-adornment {} using CSS nesting,
and restructures the adornment button rules to be co-located.

BREAKING CHANGE: consumers targeting these class names directly in their
own CSS must update to the new flat names.
Renames BEM element classes to flat names scoped by CSS nesting:
- eds-text-field__header → header
- eds-text-field__info   → info

Adds eds-text-field as the root class on the Field wrapper so the
inner elements can be properly scoped with CSS nesting — consistent
with how Radio and Checkbox add their own class to the Field wrapper.

BREAKING CHANGE: consumers targeting these class names directly in their
own CSS must update to the new flat names.
Documents the decision to use flat class names scoped by CSS nesting
for EDS 2.0 /next components, superseding the BEM-inspired naming
mentioned in ADR 0002.

Closes #5104
@millus millus changed the title fix!: convert Input and TextField BEM classes to flat class names fix!: convert Input and TextField BEM classes to flat class names + add ADR 0006 Jun 29, 2026
millus added 2 commits June 29, 2026 11:32
Inner elements of eds-input-container should not carry the eds- prefix —
only the root class does. Renames:
- eds-input      → input
- eds-adornment  → adornment
- eds-error-icon → error-icon

Also fully nests all inner element rules inside .eds-input-container
using CSS nesting, removing the separate top-level blocks.

BREAKING CHANGE: consumers targeting these class names directly in their
own CSS must update to the new flat names.
Aligns Input with the convention that only the outermost element carries
the eds- prefix:
- eds-input-container → eds-input  (root wrapper, renamed to match component)
- input               → control    (inner <input>/<textarea> element)

Also updates all cross-component references in textarea.css,
autocomplete.css, and elements.css (the :not() exclusion for base input
styles).

BREAKING CHANGE: consumers targeting eds-input-container or the input
class on the inner element must update to eds-input and control.
@millus millus changed the title fix!: convert Input and TextField BEM classes to flat class names + add ADR 0006 fix!: convert Input and TextField BEM classes to flat class names + ADR 0006 Jun 29, 2026
@millus millus changed the title fix!: convert Input and TextField BEM classes to flat class names + ADR 0006 fix!: convert Input and TextField BEM classes to flat class names Jun 29, 2026
@millus millus self-assigned this Jun 30, 2026
@pomfrida

Copy link
Copy Markdown
Collaborator

@claude review

@claude

claude Bot commented Jul 16, 2026

Copy link
Copy Markdown

Claude finished @pomfrida's task in 3m 4s —— View job


Review: fix!: convert Input and TextField BEM classes to flat class names

  • Read the full diff against origin/main
  • Review Input CSS/TSX changes
  • Review TextField changes
  • Check cross-component references (TextArea, Autocomplete, elements.css)
  • Verify snapshots and tests

Verdict: LGTM. This is a correct, mechanical BEM→flat conversion that matches the convention in AGENTS.md and ADR 0006 (single eds--prefixed root class, flat inner names scoped by CSS nesting). I found no correctness issues.

What I verified

  • No stragglers. Grepped the whole repo for eds-input-container, eds-adornment, eds-error-icon, eds-text-field__, and .eds-input — every reference is either updated or intentionally the renamed root class. The only remaining .eds-input occurrences are the three cross-component root-class references (input.css, autocomplete.css:30, textarea.css:18), which are correct.
  • Class-name swap is consistent. The tricky part of this change is that .eds-input moves from the inner <input> to the root container, and the inner control becomes .control. The :not(..., .control) exclusion in Foundation/elements.css:373 and the textarea.control selectors in textarea.css both track that swap correctly, so the inner control is still excluded from the generic .eds-elements input base styles.
  • Nesting is balanced and complete. Read the full input.css and textarea.css — no rule was dropped in the flatten→nest move. The comfortable-density rule (input.css:33) correctly became [data-density='comfortable'] &, which expands to the same [data-density='comfortable'] .eds-input selector as before.
  • Specificity. Nesting raises inner-element specificity (e.g. .eds-input .control is now 0,2,0 vs the old 0,1,0), but the relative ordering between base/hover/disabled/readonly rules is preserved, and the only external selector that could conflict (elements.css) excludes .control. Behaviour is unchanged.
  • TextField. Adding className="eds-text-field" to the Field wrapper is consistent with how Radio/Checkbox add their own class, and the snapshot correctly shows class="eds-field eds-text-field". Inner header/info are properly scoped under .eds-text-field.
  • Snapshots (Input, TextField) match the code changes.
  • Breaking change is correctly flagged with fix!: and a BREAKING CHANGE: note, since consumers targeting these class names directly must update.

Minor observations (non-blocking)

  1. Generic inner names. control, item, and text are on the vague side. They're unambiguous within their nested scope so this is fine per the convention, but item (adornment icon/button slot) and text (adornment text) read less clearly than, say, .adornment-item / .adornment-text. Purely a naming-taste call — no need to change if it matches the sibling PRs (fix!: convert Banner BEM classes to flat class names #5114, fix!: convert Field, Switch, Radio, Checkbox BEM classes to flat class names #5115).

  2. Cross-component coupling to an internal name. textarea.css:23,63 now reaches into Input's internals via textarea.control, and .eds-input (Input's root) at :18. This coupling already existed pre-PR (.eds-input was the old inner name), so it's not a regression — just worth keeping in mind that TextArea depends on Input's internal element class, which the flat convention makes slightly less obviously "internal" than the old eds--prefixed name did. If Input ever renames .control, TextArea breaks silently. Not something to fix here.

I reviewed statically; I did not run the suite in this job, but the snapshot diffs align with the source changes and the PR reports 133 passing tests across Input|TextField|TextArea|Autocomplete.
· feat/bem-to-flat-input-textfield

@vnys
vnys removed their request for review August 3, 2026 09:32

@pomfrida pomfrida left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice 👏 Approved with minor comments

[type='checkbox'], [type='radio'],
[type='range'], [type='color'], [type='file'], [type='image'],
[type='submit'], [type='reset'], [type='button'], .eds-input
[type='submit'], [type='reset'], [type='button'], .control

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.control is a really common class name, so this can now accidentally exclude a consumer's own <input class="control"> from the foundation styles. What we actually want to exclude is "an input inside our Input", so maybe:

[type='submit'], [type='reset'], [type='button'], .eds-input input

Comment on lines +96 to +97
& .text,
& .item,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adornments can contain any markup, so & .text etc. will also hit consumer elements that happen to use these class names. Everything here is a direct child, so using > (& > .adornment > .text etc.) avoids that for free. Same for & .header in text-field.css.

I realise Banner and Field/Switch/Radio/Checkbox use the same descendant pattern and I only spotted this now, so not blocking this PR on it, I can open a follow-up issue to sweep all the components and get it into the ADR. Feel free to use > here already if you agree though.

const hasEndAdornment = endText || endAdornment

const containerClasses = ['eds-input-container', containerClassName]
const containerClasses = ['eds-input', containerClassName]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since eds-input used to be the inner input and is now the container, existing CSS against it won't break visibly — it just starts styling the wrong element. Worth mentioning that in the BREAKING CHANGE note, e.g. ".eds-input is now the container; the inner input is .control." A specific footer also avoids the manual dedup we had to do in the release PR after #5114/#5115, where the identical footer texts ended up as duplicate changelog entries.

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.

chore: convert remaining /next components from BEM to flat class names

2 participants