Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent Tab component's id from clashing with DOM id #3311

Open
Dremora opened this issue Jan 9, 2024 · 2 comments
Open

Prevent Tab component's id from clashing with DOM id #3311

Dremora opened this issue Jan 9, 2024 · 2 comments

Comments

@Dremora
Copy link
Sponsor

Dremora commented Jan 9, 2024

Motivation

Consider existing Tab example: https://ariakit.org/components/tab

In order to implement controllable active tab, or specify default active tab, I need to provide tab IDs. However, these IDs seem to be also used as HTML id attribute, creating potential clashes and breaking component's encapsulation. This is different from, for example, Select component, where SelectItem's value prop is used for a similar purpose (to identify an item in a collection), but it doesn't interfere with DOM's id.

Note that other examples also suffer from the same problem of global IDs.

React Aria's Tab component is generating unique IDs to use in DOM.

I do think that the current behaviour can create hard to debug issues (and the example already has them). Of course global IDs will likely not be an issue in an example, but they very well might be in a more complex app (in our case these IDs are dynamic and come from the backend).

Workaround

The only idea I currently have is to generate a unique ID using useId(), and:

  • prepend it to all IDs that Ariakit receives
  • strip it from all IDs that are being sent back to the consumer, e.g. in TabProvider's setSelectedId callback

This is not an ideal approach, of course, as it will require string manipulation and creation of a new context so that all involved components have access to this ID (I'm working on a component library built on top of Ariakit).

Possible implementations

  • Introduce another property called value that works in a similar way but doesn't clash with DOM id.
@diegohaz
Copy link
Member

diegohaz commented Jan 9, 2024

I've already considered a idPrefix prop or something similar to address this issue of conflicting IDs:

const id = React.useId();

<TabProvider idPrefix={id}>
  <Tab id="foo" />
  <TabPanel tabId="foo" />
</Tab>

With this approach, everything is automatically prefixed, and callbacks like setSelectedId will return without the prefix. The only exception is when you're working directly with the DOM, in which case you should manually include the prefix (for example, when calling document.getElementById(`${id}foo`)).

Do you think this could be a solution to the problem?

@Dremora
Copy link
Sponsor Author

Dremora commented Jan 10, 2024

I think this approach would make things simpler that the current workaround. However, it's still not reaching the simplicity of React Aria's solution. It's a prop one needs to be aware of and remember to use when implementing tabs.

However, I also acknowledge that React Aria's approach means that getting the actual DOM id is trickier (but perhaps it's not a pattern that they encourage, I couldn't find any examples in the docs).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants