Skip to content

feat: implement ADR-023 Part 1#7724

Open
francinelucca wants to merge 37 commits intomainfrom
chore/implement-adr-023
Open

feat: implement ADR-023 Part 1#7724
francinelucca wants to merge 37 commits intomainfrom
chore/implement-adr-023

Conversation

@francinelucca
Copy link
Copy Markdown
Member

@francinelucca francinelucca commented Apr 2, 2026

Towards https://github.com/github/primer/issues/6497

Adds data-component attribute (see ADR) for:

  • ActionBar
  • ActionList
  • Button
  • FilteredActionList
  • Link
  • LinkButton
  • Pagination
  • SelectPanel
  • Table
  • TextInput
  • TextInputWithTokens
  • TooltipV2

Changelog

New

  • stable selectors for listed components
  • tests for stable selectors added

Rollout strategy

  • Patch release
  • Minor release
  • Major release; if selected, include a written rollout or migration plan
  • None; if selected, include a brief description as to why

Testing & Reviewing

Merge checklist

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 2, 2026

🦋 Changeset detected

Latest commit: 1cbc315

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@primer/react Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added staff Author is a staff member integration-tests: recommended This change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm labels Apr 2, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 2, 2026

⚠️ Action required

👋 Hi, this pull request contains changes to the source code that github/github-ui depends on. If you are GitHub staff, test these changes with github/github-ui using the integration workflow. Check the integration testing docs for step-by-step instructions. Or, apply the integration-tests: skipped manually label to skip these checks.

To publish a canary release for integration testing, apply the Canary Release label to this PR.

aria-label={ariaLabel}
icon={icon}
{...props}
// TODO: does this make sense? it'll override IconButton's data-component
Copy link
Copy Markdown
Member Author

@francinelucca francinelucca Apr 2, 2026

Choose a reason for hiding this comment

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

I feel like this indeed makes no sense, but does that mean that subcomponents like ActionBar.Menu don't have a data-component, despite being public subcomponents? how would you target them then?: [data-component="ActionBar"] [data-component="IconButton"] isn't specific enough because ActionBar.IconButton would match this as well 🤔
Should we wrap everything top-level in a span for these cases just so we can attach the data-component attribute? is there any chance for that to mess anything up?

Copy link
Copy Markdown
Member

@siddharthkp siddharthkp Apr 2, 2026

Choose a reason for hiding this comment

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

In this scenario, i think it makes sense to override the menu IconButton because there are other IconButtons in this component as well. (I'd call it ActionBar.MoreIconButton or ActionBar.MenuIconButton)

It's likely that it will be used with a classname on the ActionBar root .myActionBar [data-component=ActionBar.MoreIconButton]

That said, I don't think <Actionbar.IconButton> should get a data-component at all because

  1. they already have a data-component
  2. you can pass a classname to that

Should we wrap everything top-level in a span for these cases just so we can attach the data-component attribute?

Not a good idea because it will introduce nesting, which in best of cases is unnecessary and in the worst cases breaks dom validation rules or slots constraints


There will be other similar scenarios where we might choose to override the child's data-component when there are two distinct IconButtons that are baked in the component and not accessible in the API, for example the previous and next icon buttons in Pagination.

@github-actions github-actions Bot temporarily deployed to storybook-preview-7724 April 2, 2026 03:31 Inactive
@francinelucca francinelucca added the update snapshots 🤖 Command that updates VRT snapshots on the pull request label Apr 2, 2026
icon={icon}
{...props}
// overriding IconButton's data-component so that the ActionBar's "More Menu" Icon can be targetted specifically
data-component="ActionBar.Menu.IconButton"
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

should this be:

  • ActionBar.MenuIconButton
  • ActionBar.Menu
  • ActionBar.Menu.IconButton
    ?

I feel like this is the IconButton that belongs to the Menu that is a subcomponent of ActionBar, which is why ActionBar.Menu.IconButton makes sense to me 🤔. ActionBar.Menu seems disingenuous because really this is not the menu itself, just the Icon trigger. But I could see the case for ActionBar.MenuIconButton

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.

I vote for ActionBar.Menu.IconButton too!

Copy link
Copy Markdown
Member

@siddharthkp siddharthkp Apr 8, 2026

Choose a reason for hiding this comment

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

tl;dr: both ActionBar.MenuIconButton and ActionBar.Menu.IconButton are fine, i like one more than the other

  • ActionBar.Menu 👎 that's for the menu, not the button
  • ActionBar.Menu.IconButton it's fine, but the double dots feels weird, idk why. Maybe because ActionBar.Menu is actually a shorthand for ActionMenu... but ActionBar.ActionMenu.IconButton feels worse for some reason.
  • ActionBar.MenuIconButton: 👍 I like this the most. consistent pattern everywhere

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

what about here
image

you vote for ActionList.ItemLabel?

Copy link
Copy Markdown
Member

@siddharthkp siddharthkp Apr 9, 2026

Choose a reason for hiding this comment

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

Hmmmmmm, I know i'm being very inconsistent with my feeling or taste™, but i like ActionList.Item.Label there because ActionList.Item is where you would put your className 🤔

❌ bad:

<ActionList>
  <ActionList.Item><span className={styles.myLabel}>label</span></ActionList.Item>
</ActionList>

<style>
  .myLabel {
    font-weight: bold
  }
</style>

✅ good:

<ActionList>
  <ActionList.Item className={styles.myActionListItem}>label</ActionList.Item>
</ActionList>

<style>
  // with direct data-component, good!:
  .myActionListItem [data-component="ActionList.Item.Label"] {
    font-weight: bold
  }
</style>

I think I was wrong about ActionBar.Menu.IconButton. If ActionBar.Menu is part of the public API, then ActionBar.Menu.IconButton should be the better choice.

Do you mind also including Pagination and SelectPanel in this PR? I think those are the most opaque components, once we go through them, all the rest will be straightforward.

Comment on lines 180 to 191
<HeadingWrap
role="presentation"
className={groupClasses.GroupHeadingWrap}
aria-hidden="true"
data-variant={variant}
data-component="GroupHeadingWrap"
data-component="ActionList.GroupHeading"
as={headingWrapElement}
{...props}
>
<span className={clsx(className, groupClasses.GroupHeading)} id={groupHeadingId}>
{_internalBackwardCompatibleTitle ?? children}
</span>
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Here the actual user-supplied className is in the span within the "HeadingWrap";
Should the data-component always be where the className is? or does it make sense for it to go on the outermost element?
if so:
For this case, should we do: data-component="GroupHeading.Wrapper" and data-component="GroupHeading"?
If so:
does that mean we should always have data-component for wrappers?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

does that mean we should always have data-component for wrappers?

EDIT: no, quoting ADR: "Elements that are purely for layout and have no semantic meaning (spacers,
wrappers that exist only for CSS grid/flex layout) do not require this
attribute."

therefor also no

For this case, should we do: data-component="GroupHeading.Wrapper" and data-component="GroupHeading"?

@primer
Copy link
Copy Markdown
Contributor

primer Bot commented Apr 8, 2026

🤖 Lint issues have been automatically fixed and committed to this PR.

@francinelucca francinelucca changed the title feat(ActionBar): add data-component attributes for better accessibility feat: implement ADR-023 Part 1 Apr 8, 2026
- **TextInputwithTokens**
- **TooltipV2**

This enables consumers to query and test components using stable selectors like `[data-component="Table.Row"]`.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

General comment, that's why I'm leaving it on the changelog.

How i understand it, the problem that we're trying to solve with data-component is to expose stable selectors which otherwise would be hidden or tucked away.

Some of these components are top level components that support className and are not composed in an invisible manner inside another component (like selectpanel items), should we still add data-component to them?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

and are not composed in an invisible manner inside another component

I think this is the key here. Which one of these falls into that category? 🤔 The way I see it these all are either:

  • parts of bigger components (ex: Button inside SelectPanel, Button inside table, Tooltip inside everywhere), so we want the data-component to be able to drill down:
image
  • Big components with smaller parts (SelectPanel has ActionList, Table has Button, ActionBar has Button...), so we need the top-level data-component to "inherit from":
image

@francinelucca francinelucca added update snapshots 🤖 Command that updates VRT snapshots on the pull request and removed update snapshots 🤖 Command that updates VRT snapshots on the pull request labels Apr 20, 2026
@primer
Copy link
Copy Markdown
Contributor

primer Bot commented Apr 20, 2026

🤖 Lint issues have been automatically fixed and committed to this PR.

@github-actions github-actions Bot removed the update snapshots 🤖 Command that updates VRT snapshots on the pull request label Apr 20, 2026
@primer
Copy link
Copy Markdown
Contributor

primer Bot commented Apr 20, 2026

🤖 Lint issues have been automatically fixed and committed to this PR.

Copy link
Copy Markdown
Member

@siddharthkp siddharthkp left a comment

Choose a reason for hiding this comment

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

Please merge

@primer
Copy link
Copy Markdown
Contributor

primer Bot commented Apr 22, 2026

🤖 Lint issues have been automatically fixed and committed to this PR.

@github-actions github-actions Bot temporarily deployed to storybook-preview-7724 April 22, 2026 15:37 Inactive
@francinelucca francinelucca added the update snapshots 🤖 Command that updates VRT snapshots on the pull request label Apr 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

integration-tests: recommended This change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm staff Author is a staff member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants