huntabyte / shadcn-svelte

shadcn/ui, but for Svelte. ✨
https://shadcn-svelte.com
MIT License
4.36k stars 273 forks source link

Add multiple={true} and {max} functionalities to <Form.Select> #597

Closed dkmooers closed 4 months ago

dkmooers commented 6 months ago

Describe the feature in detail (code, mocks, or screenshots encouraged)

multiple={true} works with the basic <Select> component, but <Form.Select> hasn't implemented this yet, and can only handle single values. (I'm not sure if this is something that needs updating within Bits UI or shadcn-svelte.)

I'd also love to have a {max} prop to limit the max number of selections. Looks like bits-ui's <Select> doesn't have this yet.

I tried svelte-multiselect but it's styled totally differently, not using Tailwind at all.

I tried using the basic <Select> component instead, and I can receive value updates with the onSelectedChange callback, but I'm not sure how to manually update the values of the <Form> component (don't quite grok how that's working via formsnap - I've always rolled my own form handlers with TRPC so this is new for me). Happy to use a workaround if anyone could point me in the right direction there.

Somebody made a Multiple Selector component for React built on shadcn, not sure if this would be useful to look at:

https://shadcnui-expansions.typeart.cc/docs/multiple-selector

shadcn-svelte is an amazing UI library (best I've seen in a couple years of working with Svelte), so I'm very grateful! This is the last little feature I need for complete form building in a new web app.

What type of pull request would this be?

New Feature

Provide relevant links or additional information.

No response

dkmooers commented 6 months ago

Maybe this is an Enhancement?

dkmooers commented 6 months ago

Ah, I figured out I can do something like this with Formsnap as a workaround:

<Form.Field {config} name="secondaryGenreIds" let:value let:setValue>
  <Select.Root multiple={true} onSelectedChange={(items) => setValue(items?.map(item => item.value))}>
    ...
    {#each value as _, i}
      <input hidden aria-hidden="true" name="secondaryGenreIds" value={value[i]} />
    {/each}
  </Select.Root>
</Form.Field>

With this schema:

export const profileFormSchema = z.object({
  secondaryGenreIds: z
    .string().array().max(3, 'Choose up to 3 genres'),
    })
})

The hidden inputs above, inside the {#each} block, follow the convention from the Superforms docs here for using arrays of primitives without dataType="json". This leads to correct & valid data being received by the server (e.g. secondaryGenreIds: ['folk', 'jazz']).

However, there's some strange validation error happening here (see attached video). It works fine after opening the select, selecting the first item, and then closing the select. But then, if I re-open the select, then close it again (or focus and unfocus any other form input), the errors value changes from undefined to {}, which shows up as a red-label validation error even though there aren't any actual Zod errors.

I've been trying to dig into the code for Formsnap and SuperForms but can't figure out why this is happening. I'm guessing it's a problem with handling of arrays of primitives, but not sure how to rectify this or work around it (e.g. with a custom validator).

https://github.com/huntabyte/shadcn-svelte/assets/3757963/181639df-90dc-4940-8272-6c13901a0c98

bjornpijnacker commented 5 months ago

@dkmooers How did you get Form.Field to accept the array as a valid name? I seem to be running into the upstream issue where formsnap doesn't support Zod array types for multiselect: https://github.com/huntabyte/formsnap/issues/27

dkmooers commented 5 months ago

@bjornpijnacker Sorry for the delay! Welp, I thought I had it working since even though TS was complaining, I was still receiving the correct array of values on the server on form submit. But it looks like setting the multiselect values from my server load function isn't working properly. Sorry to disappoint. Want to +1 on this? https://github.com/huntabyte/formsnap/pull/86

dkmooers commented 5 months ago

Actually, this might be a separate issue. It looks like setting initial values even on single-selects isn't working:

https://github.com/huntabyte/shadcn-svelte/issues/717

So it could be that if that gets fixed, this multi-select initial select will work fine?

huntabyte commented 4 months ago

Closing as not relevant with updates to Formsnap and form components.

dkmooers commented 3 months ago

Just updated to Superforms v2 and the Formsnap rewrite, and this is indeed moot. Thanks for the great work @huntabyte!