diff --git a/docs/src/pages/components/RadioButton.svx b/docs/src/pages/components/RadioButton.svx index 9b24026e33..fa04623159 100644 --- a/docs/src/pages/components/RadioButton.svx +++ b/docs/src/pages/components/RadioButton.svx @@ -11,6 +11,8 @@ components: ["RadioButtonGroup", "RadioButton", "RadioButtonSkeleton"] ## Default +`RadioButton` is intended to be used within a `RadioButtonGroup`. See [Standalone usage](#standalone-usage) for individual usage. + Create a group of radio buttons with a shared name and legend. @@ -19,6 +21,12 @@ Create a group of radio buttons with a shared name and legend. +## Standalone usage + +Use `RadioButton` individually with a bindable `checked` prop for simple use cases. + + + ## Hidden legend Visually hide the legend while maintaining accessibility. diff --git a/docs/src/pages/framed/RadioButton/RadioButtonStandalone.svelte b/docs/src/pages/framed/RadioButton/RadioButtonStandalone.svelte new file mode 100644 index 0000000000..97c7d2f15a --- /dev/null +++ b/docs/src/pages/framed/RadioButton/RadioButtonStandalone.svelte @@ -0,0 +1,25 @@ + + +
+ +
+ +
+ +
diff --git a/src/RadioButton/RadioButton.svelte b/src/RadioButton/RadioButton.svelte index 3ce9aa220b..dfcdf67a2c 100644 --- a/src/RadioButton/RadioButton.svelte +++ b/src/RadioButton/RadioButton.svelte @@ -53,7 +53,11 @@ add({ id, checked, disabled, value }); } - $: checked = $selectedValue === value; + // Only sync checked when inside RadioButtonGroup. + // This allows standalone `RadioButton` usage. + $: if (add) { + checked = $selectedValue === value; + }
{ + on:change={(e) => { if (update) { update(value); + } else { + // Update `checked` for standalone `RadioButton` usage. + checked = e.currentTarget.checked; } }} /> diff --git a/tests/RadioButton/RadioButtonStandalone.test.svelte b/tests/RadioButton/RadioButtonStandalone.test.svelte new file mode 100644 index 0000000000..f3a3c17fb6 --- /dev/null +++ b/tests/RadioButton/RadioButtonStandalone.test.svelte @@ -0,0 +1,14 @@ + + + + + diff --git a/tests/RadioButton/RadioButtonStandalone.test.ts b/tests/RadioButton/RadioButtonStandalone.test.ts new file mode 100644 index 0000000000..fcf44fc536 --- /dev/null +++ b/tests/RadioButton/RadioButtonStandalone.test.ts @@ -0,0 +1,48 @@ +import { render, screen } from "@testing-library/svelte"; +import { user } from "../setup-tests"; +import RadioButtonStandalone from "./RadioButtonStandalone.test.svelte"; + +describe("RadioButton (Standalone)", () => { + it("should allow checked prop to be updated programmatically when standalone", async () => { + const { component } = render(RadioButtonStandalone, { + props: { checked: false }, + }); + + const input = screen.getByRole("radio") as HTMLInputElement; + expect(input).not.toBeChecked(); + + component.checked = true; + await new Promise((resolve) => setTimeout(resolve, 0)); + + expect(input).toBeChecked(); + + component.checked = false; + await new Promise((resolve) => setTimeout(resolve, 0)); + + expect(input).not.toBeChecked(); + }); + + it("should bind checked state when user clicks standalone radio button", async () => { + const { component } = render(RadioButtonStandalone, { + props: { checked: false }, + }); + + const input = screen.getByRole("radio"); + expect(component.checked).toBe(false); + + await user.click(input); + + expect(component.checked).toBe(true); + expect(input).toBeChecked(); + }); + + it("should support initial checked state for standalone radio button", () => { + const { component } = render(RadioButtonStandalone, { + props: { checked: true }, + }); + + const input = screen.getByRole("radio"); + expect(input).toBeChecked(); + expect(component.checked).toBe(true); + }); +});