Skip to content

Commit 04c98c5

Browse files
committed
refactor(CPopover): improve accessibility
1 parent 5dfb126 commit 04c98c5

File tree

3 files changed

+64
-45
lines changed

3 files changed

+64
-45
lines changed

packages/coreui-vue/src/components/popover/CPopover.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { defineComponent, h, PropType, ref, RendererElement, Transition } from 'vue'
1+
import { defineComponent, h, onMounted, PropType, ref, RendererElement, Transition } from 'vue'
22
import type { Placement } from '@popperjs/core'
33

44
import { CConditionalTeleport } from '../conditional-teleport'
55
import { usePopper } from '../../composables'
66
import type { Placements, Triggers } from '../../types'
77
import { executeAfterTransition } from '../../utils/transition'
8-
import { getRTLPlacement } from '../../utils'
8+
import { getRTLPlacement, getUID } from '../../utils'
99

1010
const CPopover = defineComponent({
1111
name: 'CPopover',
@@ -117,6 +117,7 @@ const CPopover = defineComponent({
117117
setup(props, { attrs, slots, emit }) {
118118
const togglerRef = ref()
119119
const popoverRef = ref()
120+
const uID = ref()
120121
const visible = ref(props.visible)
121122
const { initPopper, destroyPopper } = usePopper()
122123

@@ -147,6 +148,10 @@ const CPopover = defineComponent({
147148
placement: getRTLPlacement(props.placement, togglerRef.value),
148149
}
149150

151+
onMounted(() => {
152+
uID.value = getUID('popover')
153+
})
154+
150155
const handleEnter = (el: RendererElement, done: () => void) => {
151156
emit('show')
152157
initPopper(togglerRef.value, popoverRef.value, popperConfig)
@@ -206,6 +211,7 @@ const CPopover = defineComponent({
206211
},
207212
attrs.class,
208213
],
214+
id: uID.value,
209215
ref: popoverRef,
210216
role: 'tooltip',
211217
},
@@ -234,6 +240,7 @@ const CPopover = defineComponent({
234240
),
235241
slots.toggler &&
236242
slots.toggler({
243+
id: visible.value ? uID.value : null,
237244
on: {
238245
click: (event: Event) =>
239246
props.trigger.includes('click') && toggleVisible(event, !visible.value),

packages/coreui-vue/src/directives/v-c-popover.ts

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { DirectiveBinding } from 'vue'
22
import { createPopper } from '@popperjs/core'
33

4+
import type { Options } from '@popperjs/core'
5+
46
import { getUID } from '../utils'
57

68
const createPopoverElement = (id: string, header: string, content: string): HTMLDivElement => {
@@ -14,30 +16,40 @@ const createPopoverElement = (id: string, header: string, content: string): HTML
1416
return popover
1517
}
1618

17-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
18-
const addPopoverElement = (popover: HTMLDivElement, el: HTMLElement, popperOptions: any) => {
19+
const addPopoverElement = (
20+
el: HTMLElement,
21+
popover: HTMLDivElement,
22+
popperOptions: Partial<Options>,
23+
uID: string,
24+
) => {
25+
el.setAttribute('aria-describedby', uID)
1926
document.body.appendChild(popover)
2027
createPopper(el, popover, popperOptions)
2128
setTimeout(() => {
2229
popover.classList.add('show')
2330
}, 1)
2431
}
2532

26-
const removePopoverElement = (popover: HTMLDivElement) => {
33+
const removePopoverElement = (el: HTMLElement, popover: HTMLDivElement) => {
34+
el.removeAttribute('aria-describedby')
2735
popover.classList.remove('show')
2836
setTimeout(() => {
2937
popover.remove()
3038
}, 300)
3139
}
3240

33-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
34-
const togglePopoverElement = (popover: HTMLDivElement, el: HTMLElement, popperOptions: any) => {
41+
const togglePopoverElement = (
42+
el: HTMLElement,
43+
popover: HTMLDivElement,
44+
popperOptions: Partial<Options>,
45+
uID: string,
46+
) => {
3547
const popperElement = document.getElementById(popover.id)
3648
if (popperElement && popperElement.classList.contains('show')) {
37-
removePopoverElement(popover)
49+
removePopoverElement(el, popover)
3850
return
3951
}
40-
addPopoverElement(popover, el, popperOptions)
52+
addPopoverElement(el, popover, popperOptions, uID)
4153
}
4254

4355
export default {
@@ -65,30 +77,30 @@ export default {
6577
],
6678
}
6779

68-
const popoverUID = getUID('popover')
69-
binding.arg = popoverUID
70-
const popover = createPopoverElement(popoverUID, header, content)
80+
const uID = getUID('popover')
81+
binding.arg = uID
82+
const popover = createPopoverElement(uID, header, content)
7183

7284
trigger.includes('click') &&
7385
el.addEventListener('click', () => {
74-
togglePopoverElement(popover, el, popperOptions)
86+
togglePopoverElement(el, popover, popperOptions, uID)
7587
})
7688

7789
if (trigger.includes('focus')) {
7890
el.addEventListener('focus', () => {
79-
addPopoverElement(popover, el, popperOptions)
91+
addPopoverElement(el, popover, popperOptions, uID)
8092
})
8193
el.addEventListener('blur', () => {
82-
removePopoverElement(popover)
94+
removePopoverElement(el, popover)
8395
})
8496
}
8597

8698
if (trigger.includes('hover')) {
8799
el.addEventListener('mouseenter', () => {
88-
addPopoverElement(popover, el, popperOptions)
100+
addPopoverElement(el, popover, popperOptions, uID)
89101
})
90102
el.addEventListener('mouseleave', () => {
91-
removePopoverElement(popover)
103+
removePopoverElement(el, popover)
92104
})
93105
}
94106
},

packages/docs/components/popover.md

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ other_frameworks: popover
1111

1212
::: demo
1313
<CPopover title="Popover title" content="And here\’s some amazing content. It’s very engaging. Right?" placement="right">
14-
<template #toggler="{ on }">
15-
<CButton color="danger" size="lg" v-on="on">Click to toggle popover</CButton>
14+
<template #toggler="{ id, on }">
15+
<CButton color="danger" size="lg" :aria-describedby="id" v-on="on">Click to toggle popover</CButton>
1616
</template>
1717
</CPopover>
1818
:::
1919
```vue
2020
<CPopover title="Popover title" content="And here\’s some amazing content. It’s very engaging. Right?" placement="right">
21-
<template #toggler="{ on }">
22-
<CButton color="danger" size="lg" v-on="on">Click to toggle popover</CButton>
21+
<template #toggler="{ id, on }">
22+
<CButton color="danger" size="lg" :aria-describedby="id" v-on="on">Click to toggle popover</CButton>
2323
</template>
2424
</CPopover>
2525
```
@@ -41,45 +41,45 @@ Four options are available: top, right, bottom, and left aligned. Directions are
4141

4242
::: demo
4343
<CPopover content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="top">
44-
<template #toggler="{ on }">
45-
<CButton color="secondary" v-on="on">Popover on top</CButton>
44+
<template #toggler="{ id, on }">
45+
<CButton color="secondary" :aria-describedby="id" v-on="on">Popover on top</CButton>
4646
</template>
4747
</CPopover>
4848
<CPopover content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="right">
49-
<template #toggler="{ on }">
50-
<CButton color="secondary" v-on="on">Popover on right</CButton>
49+
<template #toggler="{ id, on }">
50+
<CButton color="secondary" :aria-describedby="id" v-on="on">Popover on right</CButton>
5151
</template>
5252
</CPopover>
5353
<CPopover content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="bottom">
54-
<template #toggler="{ on }">
55-
<CButton color="secondary" v-on="on">Popover on bottom</CButton>
54+
<template #toggler="{ id, on }">
55+
<CButton color="secondary" :aria-describedby="id" v-on="on">Popover on bottom</CButton>
5656
</template>
5757
</CPopover>
5858
<CPopover content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="left">
59-
<template #toggler="{ on }">
60-
<CButton color="secondary" v-on="on">Popover on left</CButton>
59+
<template #toggler="{ id, on }">
60+
<CButton color="secondary" :aria-describedby="id" v-on="on">Popover on left</CButton>
6161
</template>
6262
</CPopover>
6363
:::
6464
```vue
6565
<CPopover content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="top">
66-
<template #toggler="{ on }">
67-
<CButton color="secondary" v-on="on">Popover on top</CButton>
66+
<template #toggler="{ id, on }">
67+
<CButton color="secondary" :aria-describedby="id" v-on="on">Popover on top</CButton>
6868
</template>
6969
</CPopover>
7070
<CPopover content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="right">
71-
<template #toggler="{ on }">
72-
<CButton color="secondary" v-on="on">Popover on right</CButton>
71+
<template #toggler="{ id, on }">
72+
<CButton color="secondary" :aria-describedby="id" v-on="on">Popover on right</CButton>
7373
</template>
7474
</CPopover>
7575
<CPopover content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="bottom">
76-
<template #toggler="{ on }">
77-
<CButton color="secondary" v-on="on">Popover on bottom</CButton>
76+
<template #toggler="{ id, on }">
77+
<CButton color="secondary" :aria-describedby="id" v-on="on">Popover on bottom</CButton>
7878
</template>
7979
</CPopover>
8080
<CPopover content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="left">
81-
<template #toggler="{ on }">
82-
<CButton color="secondary" v-on="on">Popover on left</CButton>
81+
<template #toggler="{ id, on }">
82+
<CButton color="secondary" :aria-describedby="id" v-on="on">Popover on left</CButton>
8383
</template>
8484
</CPopover>
8585
```
@@ -110,8 +110,8 @@ You can customize the appearance of popovers using [CSS variables](#css-variable
110110
title="Custom popover"
111111
:style="customPopoverStyle"
112112
>
113-
<template #toggler="{ on }">
114-
<CButton color="secondary" v-on="on">Custom popover</CButton>
113+
<template #toggler="{ id, on }">
114+
<CButton color="secondary" :aria-describedby="id" v-on="on">Custom popover</CButton>
115115
</template>
116116
</CPopover>
117117
:::
@@ -123,8 +123,8 @@ You can customize the appearance of popovers using [CSS variables](#css-variable
123123
title="Custom popover"
124124
:style="customPopoverStyle"
125125
>
126-
<template #toggler="{ on }">
127-
<CButton color="secondary" v-on="on">Custom popover</CButton>
126+
<template #toggler="{ id, on }">
127+
<CButton color="secondary" :aria-describedby="id" v-on="on">Custom popover</CButton>
128128
</template>
129129
</CPopover>
130130
</template>
@@ -160,8 +160,8 @@ For disabled popover triggers, you may also prefer `:trigger="['hover', 'focus']
160160
placement="right"
161161
:trigger="['hover', 'focus']"
162162
>
163-
<template #toggler="{ on }">
164-
<span class="d-inline-block" :tabindex="0" v-on="on">
163+
<template #toggler="{ id, on }">
164+
<span class="d-inline-block" :tabindex="0" :aria-describedby="id" v-on="on">
165165
<CButton color="primary" disabled>Disabled button</CButton>
166166
</span>
167167
</template>
@@ -173,8 +173,8 @@ For disabled popover triggers, you may also prefer `:trigger="['hover', 'focus']
173173
placement="right"
174174
:trigger="['hover', 'focus']"
175175
>
176-
<template #toggler="{ on }">
177-
<span class="d-inline-block" :tabindex="0" v-on="on">
176+
<template #toggler="{ id, on }">
177+
<span class="d-inline-block" :tabindex="0" :aria-describedby="id" v-on="on">
178178
<CButton color="primary" disabled>Disabled button</CButton>
179179
</span>
180180
</template>

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy