radix-ui / primitives

Radix Primitives is an open-source UI component library for building high-quality, accessible design systems and web apps. Maintained by @workos.
https://radix-ui.com/primitives
MIT License
15.93k stars 833 forks source link

Support number and null values for <Select/> #3180

Open ianpaschal opened 1 month ago

ianpaschal commented 1 month ago

Feature request

Overview

<Select/> should accept values besides string (such as number or null).

Examples in other libraries

Perhaps it's more useful to simply say that there's no technical reason that this can't exist. It's true, it's not how default HTML <select/> elements behave, but that's why we use component libraries, right? To extend the basic functionality? Furthermore I've implemented my own workaround using parseInt(), toString() and a regex to my <Select/> component to use numbers as values/options.

Who does this impact? Who is this for?

I can provide many examples of where this would be useful in a project I'm working on. For example, consider the following form schema:

const playerCount = 4;

// There are more elegant ways to store these players (and create the correct number of fields), but lets keep it simple...
const matchSchema = z.object({
  player_0_id: z.string().uuid(),
  player_1_id: z.string().uuid(),
  player_2_id: z.string().uuid(),
  player_3_id: z.string().uuid(),
  winner: z.number().min(0).max(playerCount - 1),
});

type Match = z.infer<typeof matchSchema> ;

const form = useForm<Match>({
  resolver: zodResolver(matchSchema),
});

I would then want to be able to select who the winner was. I could of course populate the select with player UUIDs, but this is cumbersome and means that if, say, player 0 is swapped, I need to do additional validation to also update the winner field. It's much cleaner to store the winner as 0 | 1 | 2 | 4.

It's also possible to populate the select with '0' | '1' | '2' | '4' as values, but then I need to use z.coerce (which causes typing issues), and convert the values to numbers before submitting.

Possible, yes, but cumbersome and entirely unnecessary for a <Select/> to function.

Another example, where one might want null as a value (as many BEs use null for fields):

<Select
  options={[
    { label: 'Not applicable', value: null },
    { label: 'Foo', value: 'foo' },
    { label: 'Bar', value: 'bar' },
  ]}
/>

Additional context

As I said, I've already built a workaround to allow numbers as values in my implementation of the Radix <Select/>. I'm happy to make a pull-request and address any feedback if the team is willing to make this change. But I'd like to gauge interest (or pushback, haha) before I do so.