diff --git a/packages/bits-ui/src/lib/bits/pin-input/pin-input.svelte.ts b/packages/bits-ui/src/lib/bits/pin-input/pin-input.svelte.ts index 6f6c82ea2..c8bb7e06b 100644 --- a/packages/bits-ui/src/lib/bits/pin-input/pin-input.svelte.ts +++ b/packages/bits-ui/src/lib/bits/pin-input/pin-input.svelte.ts @@ -208,8 +208,25 @@ class PinInputRootState { }); } + keysToIgnore = [ + "Backspace", + "Delete", + "ArrowLeft", + "ArrowRight", + "ArrowUp", + "ArrowDown", + "Home", + "End", + "Escape", + "Enter", + "Tab", + "Shift", + "Control", + ]; + #onkeydown = (e: KeyboardEvent) => { const key = e.key; + if (this.keysToIgnore.includes(key)) return; if (key && this.#regexPattern && !this.#regexPattern.test(key)) { e.preventDefault(); } diff --git a/packages/tests/src/tests/pin-input/pin-input.test.ts b/packages/tests/src/tests/pin-input/pin-input.test.ts index 4fdffe43d..ad9bfe94d 100644 --- a/packages/tests/src/tests/pin-input/pin-input.test.ts +++ b/packages/tests/src/tests/pin-input/pin-input.test.ts @@ -1,7 +1,7 @@ import { render, waitFor } from "@testing-library/svelte/svelte5"; import { axe } from "jest-axe"; import { describe, it, vi } from "vitest"; -import type { PinInput } from "bits-ui"; +import { type PinInput, REGEXP_ONLY_DIGITS } from "bits-ui"; import { getTestKbd, setupUserEvents } from "../utils.js"; import PinInputTest from "./pin-input-test.svelte"; @@ -153,4 +153,23 @@ describe("pin Input", () => { expect(mockComplete).toHaveBeenCalledTimes(1); expect(mockComplete).toHaveBeenCalledWith("123456"); }); + + it("should ignore keys that do not match the pattern", async () => { + const { user, hiddenInput } = setup({ + pattern: REGEXP_ONLY_DIGITS, + }); + + await user.click(hiddenInput); + await user.keyboard("123"); + expect(hiddenInput).toHaveValue("123"); + + await user.keyboard(kbd.BACKSPACE); + await user.keyboard(kbd.BACKSPACE); + await user.keyboard(kbd.BACKSPACE); + expect(hiddenInput).toHaveValue(""); + await user.keyboard("$"); + expect(hiddenInput).toHaveValue(""); + await user.keyboard("1$"); + expect(hiddenInput).toHaveValue("1"); + }); });