Accessibility for ToggleButton

pull/2770/head
Tuğçe Küçükoğlu 2022-07-06 16:41:58 +03:00
parent 9368b036a5
commit b18b6f0858
5 changed files with 122 additions and 14 deletions

View File

@ -48,6 +48,28 @@ const ToggleButtonEvents = [
description: "Browser event"
}
]
},
{
name: "focus",
description: "Callback to invoke when the component receives focus.",
arguments: [
{
name: "event",
type: "object",
description: "Browser event"
}
]
},
{
name: "blur",
description: "Callback to invoke when the component loses focus.",
arguments: [
{
name: "event",
type: "object",
description: "Browser event"
}
]
}
];

View File

@ -47,6 +47,16 @@ export declare type ToggleButtonEmits = {
* @param {Event} event - Browser event.
*/
'change': (event: Event) => void;
/**
* Callback to invoke when the component receives focus.
* @param {Event} event - Browser event.
*/
'focus': (event: Event) => void;
/**
* Callback to invoke when the component loses focus.
* @param {Event} event - Browser event.
*/
'blur': (event: Event) => void;
}
declare class ToggleButton extends ClassComponent<ToggleButtonProps, ToggleButtonSlots, ToggleButtonEmits> { }

View File

@ -1,5 +1,6 @@
<template>
<div :class="buttonClass" @click="onClick($event)" role="checkbox" :aria-checked="modelValue" :tabindex="$attrs.disabled ? null : '0'" v-ripple>
<div :class="buttonClass" role="button" :tabindex="tabindex" :aria-pressed="modelValue" v-ripple
@click="onClick($event)" @keydown="onKeyDown($event)" @focus="onFocus($event)" @blur="onBlur($event)">
<span v-if="hasIcon" :class="iconClass"></span>
<span class="p-button-label">{{label}}</span>
</div>
@ -10,24 +11,52 @@ import Ripple from 'primevue/ripple';
export default {
name: 'ToggleButton',
emits: ['update:modelValue', 'change'],
emits: ['update:modelValue', 'change', 'click', 'focus', 'blur'],
props: {
modelValue: Boolean,
onIcon: String,
offIcon: String,
onLabel: String,
offLabel: String,
onLabel: {
type: String,
default: 'Yes'
},
offLabel: {
type: String,
default: 'No'
},
iconPos: {
type: String,
default: 'left'
},
disabled: {
type: Boolean,
default: false
},
tabindex: {
type: Number,
default: 0
}
},
methods: {
onClick(event) {
if (!this.$attrs.disabled) {
if (!this.disabled) {
this.$emit('update:modelValue', !this.modelValue);
this.$emit('change', event);
this.$emit('click', event);
}
},
onKeyDown(event) {
//space
if (event.keyCode === 32) {
this.onClick(event);
event.preventDefault();
}
},
onFocus(event) {
this.$emit('focus', event);
},
onBlur(event) {
this.$emit('blur', event);
}
},
computed: {
@ -35,7 +64,7 @@ export default {
return {
'p-button p-togglebutton p-component': true,
'p-button-icon-only': this.hasIcon && !this.hasLabel,
'p-disabled': this.$attrs.disabled,
'p-disabled': this.disabled,
'p-highlight': this.modelValue === true
}
},

View File

@ -11,10 +11,10 @@
<div class="content-section implementation">
<div class="card">
<h5>Basic</h5>
<ToggleButton v-model="checked1" onIcon="pi pi-check" offIcon="pi pi-times" />
<ToggleButton v-model="checked1" onIcon="pi pi-check" offIcon="pi pi-times" class="w-full sm:w-10rem" aria-label="Confirmation" />
<h5>Customized</h5>
<ToggleButton v-model="checked2" onLabel="I confirm" offLabel="I reject" onIcon="pi pi-check" offIcon="pi pi-times" style="width: 10em" />
<ToggleButton v-model="checked2" onLabel="I confirm" offLabel="I reject" onIcon="pi pi-check" offIcon="pi pi-times" class="w-full sm:w-10rem" aria-label="Confirmation"/>
</div>
</div>

View File

@ -107,6 +107,16 @@ export default {
<td>change</td>
<td>event: Browser event</td>
<td>Callback to invoke on value change.</td>
</tr>
<tr>
<td>focus</td>
<td>event: Browser event</td>
<td>Callback to invoke when the component receives focus.</td>
</tr>
<tr>
<td>blur</td>
<td>event: Browser event</td>
<td>Callback to invoke when the component loses focus.</td>
</tr>
</tbody>
</table>
@ -139,6 +149,43 @@ export default {
</table>
</div>
<h5>Accessibility</h5>
<DevelopmentSection>
<h6>Screen Reader</h6>
<p>ToggleButton component uses an element with <i>button</i> role and updates <i>aria-pressed</i> state for screen readers. Value to describe the component can be defined with <i>aria-labelledby</i> or <i>aria-label</i> props, it is highly suggested to use
either of these props as the component changes the label displayed which will result in screen readers to read different labels when the component receives focus. To prevent this, always provide an aria label that does not change related to state.</p>
<pre v-code><code>
&lt;span id="rememberme"&gt;Remember Me&lt;/span&gt;
&lt;ToggleButton aria-labelledby="rememberme" /&gt;
&lt;ToggleButton aria-label="Remember Me" /&gt;
</code></pre>
<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 button.</td>
</tr>
<tr>
<td><i>space</i></td>
<td>Toggles the checked state.</td>
</tr>
</tbody>
</table>
</div>
</DevelopmentSection>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
@ -155,10 +202,10 @@ export default {
<template>
<div>
<h5>Basic</h5>
<ToggleButton v-model="checked1" onIcon="pi pi-check" offIcon="pi pi-times" />
<ToggleButton v-model="checked1" onIcon="pi pi-check" offIcon="pi pi-times" class="w-full sm:w-10rem" aria-label="Confirmation" />
<h5>Customized</h5>
<ToggleButton v-model="checked2" onLabel="I confirm" offLabel="I reject" onIcon="pi pi-check" offIcon="pi pi-times" style="width: 10em" />
<ToggleButton v-model="checked2" onLabel="I confirm" offLabel="I reject" onIcon="pi pi-check" offIcon="pi pi-times" class="w-full sm:w-10rem" aria-label="Confirmation" />
</div>
</template>
@ -180,10 +227,10 @@ export default {
<template>
<div>
<h5>Basic</h5>
<ToggleButton v-model="checked1" onIcon="pi pi-check" offIcon="pi pi-times" />
<ToggleButton v-model="checked1" onIcon="pi pi-check" offIcon="pi pi-times" class="w-full sm:w-10rem" aria-label="Confirmation" />
<h5>Customized</h5>
<ToggleButton v-model="checked2" onLabel="I confirm" offLabel="I reject" onIcon="pi pi-check" offIcon="pi pi-times" style="width: 10em" />
<ToggleButton v-model="checked2" onLabel="I confirm" offLabel="I reject" onIcon="pi pi-check" offIcon="pi pi-times" class="w-full sm:w-10rem" aria-label="Confirmation" />
</div>
</template>
@ -206,10 +253,10 @@ export default {
imports: `<script src="https://unpkg.com/primevue@^3/togglebutton/togglebutton.min.js"><\\/script>`,
content: `<div id="app">
<h5>Basic</h5>
<p-togglebutton v-model="checked1" on-icon="pi pi-check" off-icon="pi pi-times"></p-togglebutton>
<p-togglebutton v-model="checked1" on-icon="pi pi-check" off-icon="pi pi-times" class="w-full sm:w-10rem" aria-label="Confirmation"></p-togglebutton>
<h5>Customized</h5>
<p-togglebutton v-model="checked2" on-label="I confirm" off-label="I reject" on-icon="pi pi-check" off-icon="pi pi-times" style="width: 10em"></p-togglebutton>
<p-togglebutton v-model="checked2" on-label="I confirm" off-label="I reject" on-icon="pi pi-check" off-icon="pi pi-times" class="w-full sm:w-10rem" aria-label="Confirmation"></p-togglebutton>
</div>
<script type="module">