feat(web,a11y): slider accessibility improvements (#8479)

* feat(web,a11y): slider accessibility improvements

* add perceivable focus outline
* label all sliders for screen readers

* chore: add IDs to all settings sliders

* chore: add comment to id prop

* fix: switch to using CSS to add outlines

* fix: reactive sliderId

* fix: bring back the slot

* fix: add aria-describedby for the subtitle

* fix: cleanup css because disabled slider cannot be focused

* fix: add border to the slider when focus is visible

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
Ben 2024-04-06 14:18:49 +00:00 committed by GitHub
parent e1f8e96e28
commit 56d27bc1b4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 102 additions and 28 deletions

View file

@ -199,25 +199,33 @@
</div>
<div class="my-3">
<SettingSwitch bind:checked={enablePassword} title={'Require password'} />
<SettingSwitch id="require-password" bind:checked={enablePassword} title={'Require password'} />
</div>
<div class="my-3">
<SettingSwitch bind:checked={showMetadata} title={'Show metadata'} />
<SettingSwitch id="show-metadata" bind:checked={showMetadata} title={'Show metadata'} />
</div>
<div class="my-3">
<SettingSwitch bind:checked={allowDownload} title={'Allow public user to download'} />
<SettingSwitch
id="allow-public-download"
bind:checked={allowDownload}
title={'Allow public user to download'}
/>
</div>
<div class="my-3">
<SettingSwitch bind:checked={allowUpload} title={'Allow public user to upload'} />
<SettingSwitch id="allow-public-upload" bind:checked={allowUpload} title={'Allow public user to upload'} />
</div>
<div class="text-sm">
{#if editingLink}
<p class="immich-form-label my-2">
<SettingSwitch bind:checked={shouldChangeExpirationTime} title={'Change expiration time'} />
<SettingSwitch
id="change-expiration-time"
bind:checked={shouldChangeExpirationTime}
title={'Change expiration time'}
/>
</p>
{:else}
<p class="immich-form-label my-2">Expire after</p>

View file

@ -4,20 +4,24 @@
import { createEventDispatcher } from 'svelte';
import Slider from '$lib/components/elements/slider.svelte';
export let id: string;
export let title: string;
export let subtitle = '';
export let checked = false;
export let disabled = false;
export let isEdited = false;
$: sliderId = `${id}-slider`;
$: subtitleId = subtitle ? `${id}-subtitle` : undefined;
const dispatch = createEventDispatcher<{ toggle: boolean }>();
const onToggle = (ischecked: boolean) => dispatch('toggle', ischecked);
const onToggle = (isChecked: boolean) => dispatch('toggle', isChecked);
</script>
<div class="flex place-items-center justify-between">
<div>
<div class="mr-2">
<div class="flex h-[26px] place-items-center gap-1">
<label class="font-medium text-immich-primary dark:text-immich-dark-primary text-sm" for={title}>
<label class="font-medium text-immich-primary dark:text-immich-dark-primary text-sm" for={sliderId}>
{title}
</label>
{#if isEdited}
@ -30,9 +34,17 @@
{/if}
</div>
<p class="text-sm dark:text-immich-dark-fg">{subtitle}</p>
{#if subtitle}
<p id={subtitleId} class="text-sm dark:text-immich-dark-fg">{subtitle}</p>
{/if}
<slot />
</div>
<Slider bind:checked {disabled} on:toggle={({ detail }) => onToggle(detail)} />
<Slider
id={sliderId}
bind:checked
{disabled}
on:toggle={({ detail }) => onToggle(detail)}
ariaDescribedBy={subtitleId}
/>
</div>