Accessibility for SelectButton
parent
519359e2d4
commit
3df8b0eb1f
|
@ -46,12 +46,6 @@ const SelectButtonProps = [
|
||||||
type: "string",
|
type: "string",
|
||||||
default: "null",
|
default: "null",
|
||||||
description: "A property to uniquely identify an option."
|
description: "A property to uniquely identify an option."
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ariaLabelledBy",
|
|
||||||
type: "string",
|
|
||||||
default: "null",
|
|
||||||
description: "Establishes relationships between the component and label(s) where its value should be one or more element IDs."
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -51,10 +51,6 @@ export interface SelectButtonProps {
|
||||||
* A property to uniquely identify an option.
|
* A property to uniquely identify an option.
|
||||||
*/
|
*/
|
||||||
dataKey?: string | undefined;
|
dataKey?: string | undefined;
|
||||||
/**
|
|
||||||
* Establishes relationships between the component and label(s) where its value should be one or more element IDs.
|
|
||||||
*/
|
|
||||||
ariaLabelledBy?: string | undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelectButtonSlots {
|
export interface SelectButtonSlots {
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="containerClass" role="group">
|
<div :class="containerClass" role="group">
|
||||||
<div v-for="(option, i) of options" :key="getOptionRenderKey(option)" :aria-label="getOptionLabel(option)" role="button" :aria-pressed="isSelected(option)"
|
<div v-for="(option, i) of options" :key="getOptionRenderKey(option)" :aria-label="getOptionLabel(option)" role="button" :aria-pressed="isSelected(option)"
|
||||||
@click="onOptionSelect($event, option, i)" @keydown.enter.prevent="onOptionSelect($event, option, i)" @keydown.space.prevent="onOptionSelect($event, option)"
|
:class="getButtonClass(option)" :tabindex="isOptionDisabled(option) ? null : '0'" v-ripple
|
||||||
:tabindex="isOptionDisabled(option) ? null : '0'" @focus="onFocus($event)" @blur="onBlur($event)" :aria-labelledby="ariaLabelledBy" v-ripple
|
@click="onOptionSelect($event, option)" @keydown="onKeydown($event, option)" @focus="onFocus($event)" @blur="onBlur($event)">
|
||||||
:class="getButtonClass(option)">
|
|
||||||
<slot name="option" :option="option" :index="i">
|
<slot name="option" :option="option" :index="i">
|
||||||
<span class="p-button-label">{{getOptionLabel(option)}}</span>
|
<span class="p-button-label">{{getOptionLabel(option)}}</span>
|
||||||
</slot>
|
</slot>
|
||||||
|
@ -26,8 +25,7 @@ export default {
|
||||||
optionDisabled: null,
|
optionDisabled: null,
|
||||||
multiple: Boolean,
|
multiple: Boolean,
|
||||||
disabled: Boolean,
|
disabled: Boolean,
|
||||||
dataKey: null,
|
dataKey: null
|
||||||
ariaLabelledBy: null
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getOptionLabel(option) {
|
getOptionLabel(option) {
|
||||||
|
@ -58,12 +56,19 @@ export default {
|
||||||
newValue = this.modelValue ? [...this.modelValue, optionValue]: [optionValue];
|
newValue = this.modelValue ? [...this.modelValue, optionValue]: [optionValue];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
newValue = optionValue;
|
newValue = selected ? null : optionValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$emit('update:modelValue', newValue);
|
this.$emit('update:modelValue', newValue);
|
||||||
this.$emit('change', {event: event, value: newValue});
|
this.$emit('change', {event: event, value: newValue});
|
||||||
},
|
},
|
||||||
|
onKeydown(event, option) {
|
||||||
|
//space
|
||||||
|
if (event.which === 32) {
|
||||||
|
this.onOptionSelect(event, option);
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
},
|
||||||
isSelected(option) {
|
isSelected(option) {
|
||||||
let selected = false;
|
let selected = false;
|
||||||
let optionValue = this.getOptionValue(option);
|
let optionValue = this.getOptionValue(option);
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<SelectButton v-model="value2" :options="paymentOptions" optionLabel="name" multiple />
|
<SelectButton v-model="value2" :options="paymentOptions" optionLabel="name" multiple />
|
||||||
|
|
||||||
<h5>Custom Content</h5>
|
<h5>Custom Content</h5>
|
||||||
<SelectButton v-model="value3" :options="justifyOptions" dataKey="value">
|
<SelectButton v-model="value3" :options="justifyOptions" optionLabel="value" dataKey="value" >
|
||||||
<template #option="slotProps">
|
<template #option="slotProps">
|
||||||
<i :class="slotProps.option.icon"></i>
|
<i :class="slotProps.option.icon"></i>
|
||||||
</template>
|
</template>
|
||||||
|
@ -45,10 +45,10 @@ export default {
|
||||||
{name: 'Option 3', value: 3}
|
{name: 'Option 3', value: 3}
|
||||||
],
|
],
|
||||||
justifyOptions: [
|
justifyOptions: [
|
||||||
{icon: 'pi pi-align-left', value: 'left'},
|
{icon: 'pi pi-align-left', value: 'Left', tabindex: 2},
|
||||||
{icon: 'pi pi-align-right', value: 'Right'},
|
{icon: 'pi pi-align-right', value: 'Right', tabindex: 2},
|
||||||
{icon: 'pi pi-align-center', value: 'Center'},
|
{icon: 'pi pi-align-center', value: 'Center', tabindex: 3},
|
||||||
{icon: 'pi pi-align-justify', value: 'Justify'}]
|
{icon: 'pi pi-align-justify', value: 'Justify', tabindex: 4}]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -117,12 +117,6 @@ export default {
|
||||||
<td>string</td>
|
<td>string</td>
|
||||||
<td>null</td>
|
<td>null</td>
|
||||||
<td>A property to uniquely identify an option.</td>
|
<td>A property to uniquely identify an option.</td>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>ariaLabelledBy</td>
|
|
||||||
<td>string</td>
|
|
||||||
<td>null</td>
|
|
||||||
<td>Establishes relationships between the component and label(s) where its value should be one or more element IDs.</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -178,6 +172,36 @@ export default {
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h5>Accessibility</h5>
|
||||||
|
<DevelopmentSection>
|
||||||
|
<h6>Screen Reader</h6>
|
||||||
|
<p>The container element that wraps the buttons has a <i>group</i> role whereas each button element uses <i>button</i> role and <i>aria-pressed</i> is updated depending on selection state.
|
||||||
|
Value to describe an option is automatically set using the <i>aria-label</i> property that refers to the label of an option so it is still suggested to define a label even the option display
|
||||||
|
consists of presentational content like icons only.</p>
|
||||||
|
|
||||||
|
<h6>Keyboard Support</h6>
|
||||||
|
<div class="doc-tablewrapper">
|
||||||
|
<table class="doc-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Key</th>
|
||||||
|
<th>Function</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><i>tab</i></td>
|
||||||
|
<td>Moves focus to the buttons.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><i>space</i></td>
|
||||||
|
<td>Toggles the checked state of a button.</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</DevelopmentSection>
|
||||||
|
|
||||||
<h5>Dependencies</h5>
|
<h5>Dependencies</h5>
|
||||||
<p>None.</p>
|
<p>None.</p>
|
||||||
</AppDoc>
|
</AppDoc>
|
||||||
|
@ -200,7 +224,7 @@ export default {
|
||||||
<SelectButton v-model="value2" :options="paymentOptions" optionLabel="name" multiple />
|
<SelectButton v-model="value2" :options="paymentOptions" optionLabel="name" multiple />
|
||||||
|
|
||||||
<h5>Custom Content</h5>
|
<h5>Custom Content</h5>
|
||||||
<SelectButton v-model="value3" :options="justifyOptions" dataKey="value">
|
<SelectButton v-model="value3" :options="justifyOptions" optionLabel="value" dataKey="value">
|
||||||
<template #option="slotProps">
|
<template #option="slotProps">
|
||||||
<i :class="slotProps.option.icon"></i>
|
<i :class="slotProps.option.icon"></i>
|
||||||
</template>
|
</template>
|
||||||
|
@ -222,7 +246,7 @@ export default {
|
||||||
{name: 'Option 3', value: 3}
|
{name: 'Option 3', value: 3}
|
||||||
],
|
],
|
||||||
justifyOptions: [
|
justifyOptions: [
|
||||||
{icon: 'pi pi-align-left', value: 'left'},
|
{icon: 'pi pi-align-left', value: 'Left'},
|
||||||
{icon: 'pi pi-align-right', value: 'Right'},
|
{icon: 'pi pi-align-right', value: 'Right'},
|
||||||
{icon: 'pi pi-align-center', value: 'Center'},
|
{icon: 'pi pi-align-center', value: 'Center'},
|
||||||
{icon: 'pi pi-align-justify', value: 'Justify'}]
|
{icon: 'pi pi-align-justify', value: 'Justify'}]
|
||||||
|
@ -244,7 +268,7 @@ export default {
|
||||||
<SelectButton v-model="value2" :options="paymentOptions" optionLabel="name" multiple />
|
<SelectButton v-model="value2" :options="paymentOptions" optionLabel="name" multiple />
|
||||||
|
|
||||||
<h5>Custom Content</h5>
|
<h5>Custom Content</h5>
|
||||||
<SelectButton v-model="value3" :options="justifyOptions" dataKey="value">
|
<SelectButton v-model="value3" :options="justifyOptions" optionLabel="value" dataKey="value">
|
||||||
<template #option="slotProps">
|
<template #option="slotProps">
|
||||||
<i :class="slotProps.option.icon"></i>
|
<i :class="slotProps.option.icon"></i>
|
||||||
</template>
|
</template>
|
||||||
|
@ -267,7 +291,7 @@ export default {
|
||||||
{name: 'Option 3', value: 3}
|
{name: 'Option 3', value: 3}
|
||||||
]);
|
]);
|
||||||
const justifyOptions = ref([
|
const justifyOptions = ref([
|
||||||
{icon: 'pi pi-align-left', value: 'left'},
|
{icon: 'pi pi-align-left', value: 'Left'},
|
||||||
{icon: 'pi pi-align-right', value: 'Right'},
|
{icon: 'pi pi-align-right', value: 'Right'},
|
||||||
{icon: 'pi pi-align-center', value: 'Center'},
|
{icon: 'pi pi-align-center', value: 'Center'},
|
||||||
{icon: 'pi pi-align-justify', value: 'Justify'}
|
{icon: 'pi pi-align-justify', value: 'Justify'}
|
||||||
|
@ -290,7 +314,7 @@ export default {
|
||||||
<p-selectbutton v-model="value2" :options="paymentOptions" option-label="name" multiple></p-selectbutton>
|
<p-selectbutton v-model="value2" :options="paymentOptions" option-label="name" multiple></p-selectbutton>
|
||||||
|
|
||||||
<h5>Custom Content</h5>
|
<h5>Custom Content</h5>
|
||||||
<p-selectbutton v-model="value3" :options="justifyOptions" data-key="value">
|
<p-selectbutton v-model="value3" :options="justifyOptions" option-label="value" data-key="value">
|
||||||
<template #option="slotProps">
|
<template #option="slotProps">
|
||||||
<i :class="slotProps.option.icon"></i>
|
<i :class="slotProps.option.icon"></i>
|
||||||
</template>
|
</template>
|
||||||
|
@ -312,7 +336,7 @@ export default {
|
||||||
{name: 'Option 3', value: 3}
|
{name: 'Option 3', value: 3}
|
||||||
]);
|
]);
|
||||||
const justifyOptions = ref([
|
const justifyOptions = ref([
|
||||||
{icon: 'pi pi-align-left', value: 'left'},
|
{icon: 'pi pi-align-left', value: 'Left'},
|
||||||
{icon: 'pi pi-align-right', value: 'Right'},
|
{icon: 'pi pi-align-right', value: 'Right'},
|
||||||
{icon: 'pi pi-align-center', value: 'Center'},
|
{icon: 'pi pi-align-center', value: 'Center'},
|
||||||
{icon: 'pi pi-align-justify', value: 'Justify'}
|
{icon: 'pi pi-align-justify', value: 'Justify'}
|
||||||
|
|
Loading…
Reference in New Issue