sveltejs / svelte

Cybernetically enhanced web apps
https://svelte.dev
MIT License
78.76k stars 4.13k forks source link

Svelte 5: Typescript error on custom radio due to bind:group not being bindable #13501

Open GeoffCox opened 1 week ago

GeoffCox commented 1 week ago

Describe the bug

When writing a custom radio input component that passes ...rest to the rendered input element, callers get a typescript error for bind:group not being bindable. This makes it impossible to create a custom radio component without re-implementing all of group behavior.

HTMLInputAttributes in svelte/elements lists 'bind:group'.

Attempted workaround #1: Added group as a local $props() variable in CustomRadio, and binding to the input element, but group is not a property on HTMLInputAttributes.

Attempted workaround #2: Added "bind:group": group as a local $props() variable in CustomRadio, but the caller error still exists.

Attempted workaround #3: Added "bind:group": group = $bindable(undefined) as a local $props() variable in CustomRadio, but the caller error still exists.

Reproduction

REPL repro

Logs

No response

System Info

Svelte 5 REPL as of 2024-10-04

Severity

blocking an upgrade

harrisi commented 1 week ago

group isn't a radio button attribute. The attribute you're thinking of is called name.

brunnerh commented 1 week ago

It's some Svelte magic to get/set the current value of multiple checkboxes/radio buttons: https://svelte.dev/docs/element-directives#bind-group

brunnerh commented 1 week ago

This makes it impossible to create a custom radio component without re-implementing all of group behavior.

You have to do that anyway unless the component contains all members of the group. See note in docs:

bind:group only works if the inputs are in the same Svelte component.

Don't know if anything about that limitation changes in Svelte 5.

GeoffCox commented 1 week ago

This isn't an issue with using a set of radios in the UI, but in writing a Svelte 5 component that wraps a radio input and can expose the same bind:group property as the native input element does with Svelte. For example, in my component UI library I have a radio component that has custom styles.

brunnerh commented 1 week ago

Looks like the previous limitation does no longer apply, also don't see any issue typing-wise, you can use an intersection:

<script lang="ts">
  import type { Snippet } from "svelte";
  import type { HTMLInputAttributes } from "svelte/elements";

  let {
    children,
    group = $bindable(), // <- required for bindings
    ...rest
  }: {
    children: Snippet;
    group?: any;
  } & HTMLInputAttributes = $props();
</script>

<input type="radio" bind:group {...rest} />
{#if children}
  <label for={rest.id}>
    {@render children()}
  </label>
{/if}
7nik commented 1 week ago

This makes it impossible to create a custom radio component without re-implementing all of group behavior.

You have to do that anyway unless the component contains all members of the group. See note in docs:

bind:group only works if the inputs are in the same Svelte component.

Don't know if anything about that limitation changes in Svelte 5.

This is a problem only for a checkbox group but not a radio group.

brunnerh commented 1 week ago

In Svelte 4 neither seem to work, in v5 only checkboxes don't work 🤔

trueadm commented 4 days ago

In Svelte 4 neither seem to work, in v5 only checkboxes don't work 🤔

Can you provide a checkboxes example that doesn't work please?

brunnerh commented 4 days ago

I am referring only to the case where the checkbox is extracted (which was never supported so far).

Separate component Local elements