Skip to content

[eslint] Update button-group-no-invalid-children rule to support selection variant and add button-group-selection-require-id rule - #9950

Merged
mgadewoll merged 7 commits into
elastic:mainfrom
mgadewoll:buttongroup/eslint-no-invalid-children-selection
Aug 25, 2026
Merged

[eslint] Update button-group-no-invalid-children rule to support selection variant and add button-group-selection-require-id rule#9950
mgadewoll merged 7 commits into
elastic:mainfrom
mgadewoll:buttongroup/eslint-no-invalid-children-selection

Conversation

@mgadewoll

@mgadewoll mgadewoll commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Note

This PR is related to #9929 which adds variant="selection" to EuiButtonGroup.
This PR should be rebased after merging the implementation PR.

  • What:
    • Extends the existing button-group-no-invalid-children ESLint rule with validation for variant="selection"
    • Adds a new button-group-selection-require-id rule that enforces a required id prop on each child button
  • Why: Part of the button group redesign work. selection variant behaves the same as segmented variants an we want to enforce expected children usage.
  • How:
    • Extends button-group-no-invalid-children to support checks on variant="selection"
    • Adds new rule button-group-selection-require-id which checks if button group children with variant="selection" each have an required id`
  • Refactors shared constants and utils for button group rule into a centralized place

Examples - button-group-no-invalid-children for variant="selection"

✅ valid

// EuiButton children only
<EuiButtonGroup legend="Format" variant="selection">
  <EuiButton id="bold">Bold</EuiButton>
  <EuiButton id="italic">Italic</EuiButton>
</EuiButtonGroup>

// EuiButtonIcon children only
<EuiButtonGroup legend="Format" variant="selection">
  <EuiButtonIcon id="bold" iconType="bold" aria-label="Bold" />
  <EuiButtonIcon id="italic" iconType="italic" aria-label="Italic" />
</EuiButtonGroup>

// EuiToolTip wrapping a valid button
<EuiButtonGroup legend="Format" variant="selection">
  <EuiButton id="bold">Bold</EuiButton>
  <EuiToolTip content="Italic text">
    <EuiButton id="italic">Italic</EuiButton>
  </EuiToolTip>
</EuiButtonGroup>

❌ invalid

// EuiButtonEmpty is not valid for selection
<EuiButtonGroup legend="Format" variant="selection">
  <EuiButtonEmpty color="text">Cancel</EuiButtonEmpty>
</EuiButtonGroup>

// mixing EuiButton and EuiButtonIcon is not allowed
<EuiButtonGroup legend="Format" variant="selection">
  <EuiButton id="bold">Bold</EuiButton>
  <EuiButtonIcon id="italic" iconType="italic" aria-label="Italic" />
</EuiButtonGroup>

Examples - button-group-selection-require-id

✅ valid

<EuiButtonGroup legend="Format" variant="selection">
  <EuiButton id="bold">Bold</EuiButton>
  <EuiToolTip content="Italic">
    <EuiButton id="italic">Italic</EuiButton>
  </EuiToolTip>
  <EuiPopover button={<EuiButton id="more">More</EuiButton>} isOpen={false} closePopover={() => {}}>
    Panel content
  </EuiPopover>
</EuiButtonGroup>

❌ invalid

// missing id on direct child
<EuiButtonGroup legend="Format" variant="selection">
  <EuiButton>Bold</EuiButton>
</EuiButtonGroup>

// missing id on button inside EuiToolTip
<EuiButtonGroup legend="Format" variant="selection">
  <EuiToolTip content="Italic">
    <EuiButton>Italic</EuiButton>
  </EuiToolTip>
</EuiButtonGroup>

// missing id on EuiPopover trigger
<EuiButtonGroup legend="Format" variant="selection">
  <EuiPopover button={<EuiButton>More</EuiButton>} isOpen={false} closePopover={() => {}}>
    Panel content
  </EuiPopover>
</EuiButtonGroup>

What the rules validate for variant="selection"

  1. button-group-no-invalid-children:
  • Valid direct children: EuiButton, EuiButtonIcon
  • Valid wrappers: same as other variants (EuiToolTip, EuiPopover, EuiCopy)
  • Mixed types: reports invalidMixedTypes when both EuiButton and EuiButtonIcon appear in the same group
  1. button-group-selection-require-id:
  • Reports missingId for any EuiButton/EuiButtonIcon without an explicit id attribute
  • Spread props ({...props}) are skipped conservatively (id may be passed via the spread)
  • Only fires for variant="selection" (static string); dynamic variants are skipped

API Changes

⚪ No API changes

Screenshots

Screenshot 2026-08-24 at 17 43 55 Screenshot 2026-08-24 at 17 43 15

Impact Assessment

Note: Most PRs should be tested in Kibana to help gauge their Impact before merging.

  • 🔴 Breaking changes — What will break? How many usages in Kibana/Cloud UI are impacted?
  • 💅 Visual changes — May impact style overrides; could require visual testing. Explain and estimate impact.
  • 🧪 Test impact — May break functional or snapshot tests (e.g., HTML structure, class names, default values).
  • 🔧 Hard to integrate — If changes require substantial updates to Kibana, please stage the changes and link them here.

Impact level: 🟢 None

Release Readiness

  • Documentation: {link to docs page(s)}
  • Figma: {link to Figma or issue}
  • Migration guide: {steps or link, for breaking/visual changes or deprecations}
  • Adoption plan (new features): {link to issue/doc or outline who will integrate this and where}

QA instructions for reviewer

  • CI passes
  • verify locally the rules apply and flag invalid usages
    • checkout the PR
    • run yarn workspace @elastic/eslint-plugin-eui build on root
    • run yarn workspace @elastic/eui build:workspaces on root
    • add a testing code example (e.g. see above) and run yarn workspace @elastic/eui lint on root

Checklist before marking Ready for Review

Reviewer checklist

  • Approved Impact Assessment — Acceptable to merge given the consumer impact.
  • Approved Release Readiness — Docs, Figma, and migration info are sufficient to ship.

@mgadewoll mgadewoll self-assigned this Aug 24, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the @elastic/eslint-plugin-eui rules that validate EuiButtonGroup Children API usage to support the new variant="selection" behavior and to enforce that selection children provide ids.

Changes:

  • Extend button-group-no-invalid-children validation to include variant="selection" and enforce the same “no mixed EuiButton/EuiButtonIcon types” rule as segmented.
  • Add button-group-selection-require-id to require id on EuiButton/EuiButtonIcon children (including supported wrappers) when variant="selection".
  • Refactor shared constants/utilities into centralized utils/ modules and update docs/changelog.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/eslint-plugin/src/utils/collect_jsx_children.ts New shared helper to collect JSX element “leaf” children via walkJsxChildren.
packages/eslint-plugin/src/utils/button_group_constants.ts Centralizes button-group-related constants (valid buttons/wrappers).
packages/eslint-plugin/src/rules/button_group_selection_require_id.ts New rule enforcing required id on selection-variant children (and supported wrapper patterns).
packages/eslint-plugin/src/rules/button_group_selection_require_id.test.ts Adds unit coverage for the new button-group-selection-require-id rule.
packages/eslint-plugin/src/rules/button_group_no_invalid_children.ts Updates existing rule to validate variant="selection" and generalizes mixed-type error messaging.
packages/eslint-plugin/src/rules/button_group_no_invalid_children.test.ts Updates/extends tests for selection variant validation and new mixed-type message shape.
packages/eslint-plugin/src/index.ts Registers the new rule and enables it in the recommended config.
packages/eslint-plugin/README.md Documents selection-variant behavior for both rules, including examples.
packages/eslint-plugin/changelogs/upcoming/9950.md Changelog entry for the rule update + new rule.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/eslint-plugin/src/rules/button_group_no_invalid_children.ts Outdated
Comment thread packages/eslint-plugin/src/rules/button_group_selection_require_id.test.ts Outdated
@mgadewoll
mgadewoll marked this pull request as ready for review August 25, 2026 06:26
@mgadewoll
mgadewoll requested a review from a team as a code owner August 25, 2026 06:26
Comment thread packages/eslint-plugin/src/rules/button_group_selection_require_id.ts Outdated

@weronikaolejniczak weronikaolejniczak left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM 🟢 Only one non-blocking comment.

@infra-vault-gh-plugin-prod

Copy link
Copy Markdown

💚 Build Succeeded

History

cc @mgadewoll

@infra-vault-gh-plugin-prod

Copy link
Copy Markdown

💚 Build Succeeded

History

cc @mgadewoll

@mgadewoll
mgadewoll merged commit 8c87f60 into elastic:main Aug 25, 2026
7 checks passed
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.

3 participants