diff --git a/src/lib/holocene/checkbox.svelte b/src/lib/holocene/checkbox.svelte index d32dbdca28..a658d796cb 100644 --- a/src/lib/holocene/checkbox.svelte +++ b/src/lib/holocene/checkbox.svelte @@ -75,6 +75,9 @@ : checked ? ('checkmark' as const) : null; + + $: errorId = `${id}-error`; + $: showError = !valid && !!error;
- {#if !valid && error} - {error} + {#if showError} + {error} {/if}
diff --git a/src/lib/holocene/combobox/combobox.svelte b/src/lib/holocene/combobox/combobox.svelte index ea8d92819e..c339627afb 100644 --- a/src/lib/holocene/combobox/combobox.svelte +++ b/src/lib/holocene/combobox/combobox.svelte @@ -462,6 +462,9 @@ }); } + const errorId = $derived(`${id}-error`); + const showError = $derived(!!error && !valid); + const handleInputClick: MouseEventHandler = (event) => { event.stopPropagation(); if (!$open) openList(); @@ -556,6 +559,8 @@ aria-controls="{id}-listbox" aria-expanded={$open} aria-required={required} + aria-invalid={showError ? 'true' : undefined} + aria-describedby={showError ? errorId : undefined} aria-autocomplete="list" onfocus={handleFocus} onblur={handleBlur} @@ -680,8 +685,8 @@ {/if} - {#if error && !valid} - {error} + {#if showError} + {error} {/if} diff --git a/src/lib/holocene/input/chip-input.svelte b/src/lib/holocene/input/chip-input.svelte index 0e81859c73..426f3c33fa 100644 --- a/src/lib/holocene/input/chip-input.svelte +++ b/src/lib/holocene/input/chip-input.svelte @@ -47,6 +47,7 @@ let displayValue = $state(''); const invalid = $derived(chips.some((chip) => !validator(chip))); + const errorId = $derived(`${id}-error`); const handleKeydown = (e: KeyboardEvent) => { e.stopPropagation(); @@ -144,6 +145,8 @@ {id} {name} {required} + aria-invalid={invalid ? 'true' : undefined} + aria-describedby={invalid && hintText ? errorId : undefined} multiple data-testid={id} bind:value={displayValue} @@ -159,9 +162,11 @@ {#if (invalid && hintText) || (maxLength && !disabled)}
{#if invalid && hintText}

{hintText}

diff --git a/src/lib/holocene/input/input.svelte b/src/lib/holocene/input/input.svelte index 309fef7ff1..f3d01303c3 100644 --- a/src/lib/holocene/input/input.svelte +++ b/src/lib/holocene/input/input.svelte @@ -79,6 +79,8 @@ const isDisabled = $derived(disabled || copyable); const testId = $derived(dataTestId || id); + const errorId = $derived(`${id}-error`); + const showError = $derived(error || !valid); function callFocus(input: HTMLInputElement) { if (autoFocus && input) input.focus(); @@ -134,6 +136,8 @@ {name} {spellcheck} {required} + aria-invalid={showError ? 'true' : undefined} + aria-describedby={showError && hintText ? errorId : undefined} {autocomplete} bind:value onclick={(e) => { @@ -191,10 +195,11 @@ class:hidden={!hintText && (!maxLength || isDisabled || hideCount)} > {hintText} diff --git a/src/lib/holocene/input/number-input.svelte b/src/lib/holocene/input/number-input.svelte index a21da517ff..7b6bf3e251 100644 --- a/src/lib/holocene/input/number-input.svelte +++ b/src/lib/holocene/input/number-input.svelte @@ -37,6 +37,8 @@ $: { validate(value); } + + $: errorId = `${id}-error`;
@@ -66,6 +68,8 @@ {name} {step} {required} + aria-invalid={!valid ? 'true' : undefined} + aria-describedby={!valid && hintText ? errorId : undefined} {autocomplete} spellcheck="false" bind:value @@ -86,7 +90,9 @@
{#if !valid && hintText} - {hintText} + {hintText} {/if}