diff --git a/src/lib/components/Toggle.svelte b/src/lib/components/Toggle.svelte
index 1457659f..fb5e8887 100644
--- a/src/lib/components/Toggle.svelte
+++ b/src/lib/components/Toggle.svelte
@@ -11,14 +11,38 @@
const dispatch = createEventDispatcher();
const id = nextElementId("toggle-");
+
+ let input: HTMLInputElement | undefined;
+
+ const onKeyDown = ({ code }: KeyboardEvent) => {
+ if (code !== "Space") {
+ return;
+ }
+
+ input?.click();
+ };
+
+ let toggle = checked;
+
+ const onInput = (checked: boolean) => {
+ dispatch("nnsToggle", checked);
+ toggle = checked;
+ };
-
+
- dispatch("nnsToggle", currentTarget.checked)}
+ on:input={({ currentTarget }) => onInput(currentTarget.checked)}
{checked}
aria-label={ariaLabel}
{disabled}
@@ -37,6 +61,8 @@
align-items: center;
margin-top: 1px;
+ width: fit-content;
+
&.disabled {
opacity: var(--toggle-disabled-opacity, 0.25);
}
diff --git a/src/tests/lib/components/Toggle.spec.ts b/src/tests/lib/components/Toggle.spec.ts
index a8a9c40d..897dc73d 100644
--- a/src/tests/lib/components/Toggle.spec.ts
+++ b/src/tests/lib/components/Toggle.spec.ts
@@ -1,5 +1,5 @@
import Toggle from "$lib/components/Toggle.svelte";
-import { fireEvent, render } from "@testing-library/svelte";
+import { fireEvent, render, waitFor } from "@testing-library/svelte";
describe("Toggle", () => {
const props = {
@@ -53,4 +53,54 @@ describe("Toggle", () => {
expect(onToggle).toBeCalled();
});
+
+ it("should toggle checked with keyboard", () => {
+ const { component, container } = render(Toggle, { props });
+
+ const toggle = container.querySelector("div.toggle") as HTMLDivElement;
+
+ const onToggle = vi.fn();
+ component.$on("nnsToggle", onToggle);
+
+ fireEvent.keyDown(toggle, { code: "Space" });
+
+ expect(onToggle).toBeCalled();
+ });
+
+ it("should not toggle checked with another keyboard event than Space", () => {
+ const { component, container } = render(Toggle, { props });
+
+ const toggle = container.querySelector("div.toggle") as HTMLDivElement;
+
+ const onToggle = vi.fn();
+ component.$on("nnsToggle", onToggle);
+
+ fireEvent.keyDown(toggle, { code: "a" });
+
+ expect(onToggle).not.toBeCalled();
+ expect(toggle.getAttribute("aria-pressed")).toEqual("false");
+ });
+
+ it("should reflect toggle state on aria pressed", async () => {
+ const { container } = render(Toggle, { props });
+
+ const toggle = container.querySelector("div.toggle") as HTMLDivElement;
+
+ expect(toggle.getAttribute("aria-pressed")).toEqual("false");
+
+ fireEvent.keyDown(toggle, { code: "Space" });
+
+ await waitFor(() =>
+ expect(toggle.getAttribute("aria-pressed")).toEqual("true"),
+ );
+ });
+
+ it("should have an accessible toggle", () => {
+ const { container } = render(Toggle, { props });
+
+ const toggle = container.querySelector("div.toggle") as HTMLDivElement;
+
+ expect(toggle.getAttribute("role")).toEqual("button");
+ expect(toggle.getAttribute("tabindex")).toEqual("0");
+ });
});