radix-ui / themes

Radix Themes is an open-source component library optimized for fast development, easy maintenance, and accessibility. Maintained by @workos.
https://radix-ui.com/themes
MIT License
5.33k stars 190 forks source link

TextField.Slot element tab order is always after the input #545

Closed dan-j closed 2 months ago

dan-j commented 2 months ago

I'm trying to create an extension of the TextField component where I have a Select in the left-hand slot, see screenshot:

image

The issue I've ran into is the tab-order of TextField.Root children is always after the <input />. Ideally I want the select field to be focused before the input.

I've got a patch here (ignore white-space difference, I made this from the GitHub UI): https://github.com/radix-ui/themes/compare/main...dan-j:themes:patch-1

It simply tries to convert children to an array, and will put the first child before the <input />. This seems a bit brutish, but since the external API of <TextField.Slot /> is to render on the left/right hand side in that order, it kind of matches the behaviour.

One could try to improve the solution by checking for the side prop or data-side attribute and rendering on the correct side accordingly, but looking for feedback from the community first.

I'm a relatively new user to Radix, this is my first issue! Happy to contribute fixes if the maintainers are in agreement.

vladmoroz commented 2 months ago

This was discussed and considered in depth during the latest iteration of the Text Field component. Essentially, there's no bulletproof way to position children based on their props—the slot part may be supplied as an abstracted component where you wouldn't have full access to the elements it actually renders to check the prop values.

That said, the visual style of the input focus ring is designed to wrap the whole container and feel relatively natural with this tab order, and you could argue that placing action items on the right is a bit more idiomatic with inputs.

dan-j commented 2 months ago

So in my use case, the tab order is important because I may also have an enabled/disabled action item on the right dependent on the value of the select on the left. This is essentially an input where the user is in control of whether the input represents a string/number/boolean, with the ability to insert fixed values into the input from the action button on the left.

If the child component was abstracted so there wasn't a slot prop, then isn't the current behaviour to render left then right anyway, so rendering the first child before the input wouldn't adversely affect anything?

Furthermore, most of the use-cases in the docs is the left hand slot be an icon rather than something to interact with, which isn't focusable anyway, so again if it was rendered before the input element within the DOM, it wouldn't affect tab order either?

vladmoroz commented 2 months ago

This was considered beyond the use cases displayed in the docs. With what you are proposing, there are tradeoffs that we had decided against.

If the tab order is that important in your use case, you can always build your own component or abstraction that would work exactly as you want.