mirror of
https://github.com/open-webui/open-webui.git
synced 2026-02-24 04:00:31 +01:00
fix(a11y): enhance accessibility for chat settings components (#21715)
This commit adds aria-labels to the text inputs and textareas that previously lacked them, applies role=switch to inputs, and adds accessible titles to floating quick actions.
This commit is contained in:
@@ -150,6 +150,7 @@
|
||||
class="w-full text-sm dark:text-gray-300 bg-transparent outline-hidden"
|
||||
type="text"
|
||||
bind:value={name}
|
||||
aria-label={$i18n.t('Name')}
|
||||
required
|
||||
placeholder={$i18n.t('Enter your name')}
|
||||
/>
|
||||
@@ -164,6 +165,7 @@
|
||||
className="w-full text-sm dark:text-gray-300 bg-transparent outline-hidden"
|
||||
minSize={60}
|
||||
bind:value={bio}
|
||||
ariaLabel={$i18n.t('Bio')}
|
||||
placeholder={$i18n.t('Share your background and interests')}
|
||||
/>
|
||||
</div>
|
||||
@@ -176,6 +178,7 @@
|
||||
<select
|
||||
class="w-full text-sm dark:text-gray-300 bg-transparent outline-hidden"
|
||||
bind:value={_gender}
|
||||
aria-label={$i18n.t('Gender')}
|
||||
on:change={(e) => {
|
||||
console.log(_gender);
|
||||
|
||||
@@ -199,6 +202,7 @@
|
||||
class="w-full text-sm dark:text-gray-300 bg-transparent outline-hidden mt-1"
|
||||
type="text"
|
||||
required
|
||||
aria-label={$i18n.t('Custom Gender')}
|
||||
placeholder={$i18n.t('Enter your gender')}
|
||||
bind:value={gender}
|
||||
/>
|
||||
@@ -212,6 +216,7 @@
|
||||
<input
|
||||
class="w-full text-sm dark:text-gray-300 dark:placeholder:text-gray-300 bg-transparent outline-hidden"
|
||||
type="date"
|
||||
aria-label={$i18n.t('Birth Date')}
|
||||
bind:value={dateOfBirth}
|
||||
required
|
||||
/>
|
||||
@@ -232,6 +237,7 @@
|
||||
class="w-full text-sm outline-hidden"
|
||||
type="url"
|
||||
placeholder={$i18n.t('Enter your webhook URL')}
|
||||
aria-label={$i18n.t('Notification Webhook')}
|
||||
bind:value={webhookUrl}
|
||||
required
|
||||
/>
|
||||
@@ -273,6 +279,7 @@
|
||||
|
||||
<button
|
||||
class="ml-1.5 px-1.5 py-1 dark:hover:bg-gray-850 transition rounded-lg"
|
||||
aria-label={$i18n.t('Copy Token')}
|
||||
on:click={() => {
|
||||
copyToClipboard(localStorage.token);
|
||||
JWTTokenCopied = true;
|
||||
@@ -331,6 +338,7 @@
|
||||
|
||||
<button
|
||||
class="ml-1.5 px-1.5 py-1 dark:hover:bg-gray-850 transition rounded-lg"
|
||||
aria-label={$i18n.t('Copy API Key')}
|
||||
on:click={() => {
|
||||
copyToClipboard(APIKey);
|
||||
APIKeyCopied = true;
|
||||
@@ -376,6 +384,7 @@
|
||||
<Tooltip content={$i18n.t('Create new key')}>
|
||||
<button
|
||||
class=" px-1.5 py-1 dark:hover:bg-gray-850transition rounded-lg"
|
||||
aria-label={$i18n.t('Create new key')}
|
||||
on:click={() => {
|
||||
createAPIKeyHandler();
|
||||
}}
|
||||
|
||||
@@ -186,6 +186,7 @@
|
||||
<select
|
||||
class="w-fit pr-8 rounded-sm px-2 p-1 text-xs bg-transparent outline-hidden text-right"
|
||||
bind:value={STTEngine}
|
||||
aria-label={$i18n.t('Speech-to-Text Engine')}
|
||||
placeholder={$i18n.t('Select an engine')}
|
||||
>
|
||||
<option value="">{$i18n.t('Default')}</option>
|
||||
@@ -207,6 +208,7 @@
|
||||
<input
|
||||
type="text"
|
||||
bind:value={STTLanguage}
|
||||
aria-label={$i18n.t('Speech-to-Text Language')}
|
||||
placeholder={$i18n.t('e.g. en')}
|
||||
class=" text-sm text-right bg-transparent dark:text-gray-300 outline-hidden"
|
||||
/>
|
||||
@@ -226,6 +228,8 @@
|
||||
toggleSpeechAutoSend();
|
||||
}}
|
||||
type="button"
|
||||
role="switch"
|
||||
aria-checked={speechAutoSend}
|
||||
>
|
||||
{#if speechAutoSend === true}
|
||||
<span class="ml-2 self-center">{$i18n.t('On')}</span>
|
||||
@@ -245,6 +249,7 @@
|
||||
<select
|
||||
class="w-fit pr-8 rounded-sm px-2 p-1 text-xs bg-transparent outline-hidden text-right"
|
||||
bind:value={TTSEngine}
|
||||
aria-label={$i18n.t('Text-to-Speech Engine')}
|
||||
placeholder={$i18n.t('Select an engine')}
|
||||
>
|
||||
<option value="">{$i18n.t('Default')}</option>
|
||||
@@ -260,6 +265,7 @@
|
||||
<select
|
||||
class="w-fit pr-8 rounded-sm px-2 p-1 text-xs bg-transparent outline-hidden text-right"
|
||||
bind:value={TTSEngineConfig.dtype}
|
||||
aria-label={$i18n.t('Kokoro.js Dtype')}
|
||||
placeholder={$i18n.t('Select dtype')}
|
||||
>
|
||||
<option value="" disabled selected>{$i18n.t('Select dtype')}</option>
|
||||
@@ -281,6 +287,8 @@
|
||||
toggleResponseAutoPlayback();
|
||||
}}
|
||||
type="button"
|
||||
role="switch"
|
||||
aria-checked={responseAutoPlayback}
|
||||
>
|
||||
{#if responseAutoPlayback === true}
|
||||
<span class="ml-2 self-center">{$i18n.t('On')}</span>
|
||||
@@ -299,6 +307,7 @@
|
||||
min="0"
|
||||
step="0.01"
|
||||
bind:value={playbackRate}
|
||||
aria-label={$i18n.t('Speech Playback Speed')}
|
||||
class=" text-sm text-right bg-transparent dark:text-gray-300 outline-hidden"
|
||||
/>
|
||||
x
|
||||
@@ -318,6 +327,7 @@
|
||||
list="voice-list"
|
||||
class="w-full text-sm bg-transparent dark:text-gray-300 outline-hidden"
|
||||
bind:value={voice}
|
||||
aria-label={$i18n.t('Voice')}
|
||||
placeholder={$i18n.t('Select a voice')}
|
||||
/>
|
||||
|
||||
@@ -355,6 +365,7 @@
|
||||
<select
|
||||
class="w-full text-sm bg-transparent dark:text-gray-300 outline-hidden"
|
||||
bind:value={voice}
|
||||
aria-label={$i18n.t('Voice')}
|
||||
>
|
||||
<option value="" selected={voice !== ''}>{$i18n.t('Default')}</option>
|
||||
{#each voices.filter((v) => nonLocalVoices || v.localService === true) as _voice}
|
||||
@@ -386,6 +397,7 @@
|
||||
list="voice-list"
|
||||
class="w-full text-sm bg-transparent dark:text-gray-300 outline-hidden"
|
||||
bind:value={voice}
|
||||
aria-label={$i18n.t('Voice')}
|
||||
placeholder={$i18n.t('Select a voice')}
|
||||
/>
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<Tooltip content={$i18n.t(`Add Connection`)}>
|
||||
<button
|
||||
class="px-1"
|
||||
aria-label={$i18n.t('Add Connection')}
|
||||
on:click={() => {
|
||||
showConnectionModal = true;
|
||||
}}
|
||||
|
||||
@@ -269,6 +269,8 @@
|
||||
toggleNotification();
|
||||
}}
|
||||
type="button"
|
||||
role="switch"
|
||||
aria-checked={notificationEnabled}
|
||||
>
|
||||
{#if notificationEnabled === true}
|
||||
<span class="ml-2 self-center">{$i18n.t('On')}</span>
|
||||
@@ -306,6 +308,7 @@
|
||||
? 'text-gray-800 dark:text-gray-100'
|
||||
: 'text-gray-400 dark:text-gray-500'}"
|
||||
type="button"
|
||||
aria-expanded={showAdvanced}
|
||||
on:click={() => {
|
||||
showAdvanced = !showAdvanced;
|
||||
}}>{showAdvanced ? $i18n.t('Hide') : $i18n.t('Show')}</button
|
||||
|
||||
@@ -129,12 +129,14 @@
|
||||
<input
|
||||
class=" self-center text-xs outline-none w-20"
|
||||
placeholder={$i18n.t('Button Label')}
|
||||
aria-label={$i18n.t('Button Label')}
|
||||
bind:value={button.label}
|
||||
/>
|
||||
|
||||
<input
|
||||
class=" self-center text-xs outline-none w-20 text-gray-600 dark:text-gray-400"
|
||||
placeholder={$i18n.t('Button ID')}
|
||||
aria-label={$i18n.t('Button ID')}
|
||||
bind:value={button.id}
|
||||
/>
|
||||
</div>
|
||||
@@ -143,12 +145,14 @@
|
||||
<Textarea
|
||||
className=" self-center text-xs w-full outline-none"
|
||||
placeholder={$i18n.t('Button Prompt')}
|
||||
ariaLabel={$i18n.t('Button Prompt')}
|
||||
minSize={30}
|
||||
bind:value={button.prompt}
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
class="pl-3 text-xs flex rounded-sm transition"
|
||||
aria-label={$i18n.t('Remove action')}
|
||||
on:click={() => {
|
||||
floatingActionButtons = floatingActionButtons.filter(
|
||||
(b) => b.id !== button.id
|
||||
|
||||
@@ -62,9 +62,9 @@
|
||||
>{$i18n.t('Image Max Compression Size width')}</label
|
||||
>
|
||||
<input
|
||||
id="image-comp-width"
|
||||
bind:value={size.width}
|
||||
type="number"
|
||||
aria-labelledby="image-comp-width"
|
||||
class="w-full bg-transparent outline-hidden text-center"
|
||||
min="0"
|
||||
placeholder={$i18n.t('Width')}
|
||||
@@ -80,9 +80,9 @@
|
||||
>{$i18n.t('Image Max Compression Size height')}</label
|
||||
>
|
||||
<input
|
||||
id="image-comp-height"
|
||||
bind:value={size.height}
|
||||
type="number"
|
||||
aria-labelledby="image-comp-height"
|
||||
class="w-full bg-transparent outline-hidden text-center"
|
||||
min="0"
|
||||
placeholder={$i18n.t('Height')}
|
||||
|
||||
@@ -358,6 +358,7 @@
|
||||
<div class="text-lg font-medium self-center">{$i18n.t('Sync Usage Stats')}</div>
|
||||
<button
|
||||
class="self-center"
|
||||
aria-label={$i18n.t('Close modal')}
|
||||
on:click={() => {
|
||||
show = false;
|
||||
}}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
export let readonly = false;
|
||||
export let className =
|
||||
'w-full rounded-lg px-3.5 py-2 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden h-full';
|
||||
export let ariaLabel = null;
|
||||
|
||||
export let onInput = () => {};
|
||||
export let onBlur = () => {};
|
||||
@@ -53,6 +54,7 @@
|
||||
bind:this={textareaElement}
|
||||
bind:value
|
||||
{placeholder}
|
||||
aria-label={ariaLabel || placeholder}
|
||||
class={className}
|
||||
style="field-sizing: content;"
|
||||
{rows}
|
||||
|
||||
Reference in New Issue
Block a user