Skip to content

Commit 3911802

Browse files
committed
refactor(CTooltip): improve accessibility
1 parent 04c98c5 commit 3911802

File tree

3 files changed

+60
-41
lines changed

3 files changed

+60
-41
lines changed

packages/coreui-vue/src/components/tooltip/CTooltip.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 CTooltip = defineComponent({
1111
name: 'CTooltip',
@@ -113,6 +113,7 @@ const CTooltip = defineComponent({
113113
setup(props, { attrs, slots, emit }) {
114114
const togglerRef = ref()
115115
const tooltipRef = ref()
116+
const uID = ref()
116117
const visible = ref(props.visible)
117118
const { initPopper, destroyPopper } = usePopper()
118119

@@ -143,6 +144,10 @@ const CTooltip = defineComponent({
143144
placement: getRTLPlacement(props.placement, togglerRef.value),
144145
}
145146

147+
onMounted(() => {
148+
uID.value = getUID('tooltip')
149+
})
150+
146151
const handleEnter = (el: RendererElement, done: () => void) => {
147152
emit('show')
148153
initPopper(togglerRef.value, tooltipRef.value, popperConfig)
@@ -202,6 +207,7 @@ const CTooltip = defineComponent({
202207
},
203208
attrs.class,
204209
],
210+
id: uID.value,
205211
ref: tooltipRef,
206212
role: 'tooltip',
207213
},
@@ -222,6 +228,7 @@ const CTooltip = defineComponent({
222228
),
223229
slots.toggler &&
224230
slots.toggler({
231+
id: visible.value ? uID.value : null,
225232
on: {
226233
click: (event: Event) =>
227234
props.trigger.includes('click') && toggleVisible(event, !visible.value),

packages/coreui-vue/src/directives/v-c-tooltip.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 createTooltipElement = (id: string, content: string): HTMLDivElement => {
@@ -13,30 +15,40 @@ const createTooltipElement = (id: string, content: string): HTMLDivElement => {
1315
return tooltip
1416
}
1517

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

25-
const removeTooltipElement = (tooltip: HTMLDivElement) => {
32+
const removeTooltipElement = (el: HTMLElement, tooltip: HTMLDivElement) => {
33+
el.removeAttribute('aria-describedby')
2634
tooltip.classList.remove('show')
2735
setTimeout(() => {
2836
tooltip.remove()
2937
}, 300)
3038
}
3139

32-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
33-
const toggleTooltipElement = (tooltip: HTMLDivElement, el: HTMLElement, popperOptions: any) => {
40+
const toggleTooltipElement = (
41+
el: HTMLElement,
42+
tooltip: HTMLDivElement,
43+
popperOptions: Partial<Options>,
44+
uID: string,
45+
) => {
3446
const popperElement = document.getElementById(tooltip.id)
3547
if (popperElement && popperElement.classList.contains('show')) {
36-
removeTooltipElement(tooltip)
48+
removeTooltipElement(el, tooltip)
3749
return
3850
}
39-
addTooltipElement(tooltip, el, popperOptions)
51+
addTooltipElement(el, tooltip, popperOptions, uID)
4052
}
4153

4254
export default {
@@ -62,30 +74,30 @@ export default {
6274
],
6375
}
6476

65-
const tooltipUID = getUID('tooltip')
66-
binding.arg = tooltipUID
67-
const tooltip = createTooltipElement(tooltipUID, content)
77+
const uID = getUID('tooltip')
78+
binding.arg = uID
79+
const tooltip = createTooltipElement(uID, content)
6880

6981
trigger.includes('click') &&
7082
el.addEventListener('click', () => {
71-
toggleTooltipElement(tooltip, el, popperOptions)
83+
toggleTooltipElement(el, tooltip, popperOptions, uID)
7284
})
7385

7486
if (trigger.includes('focus')) {
7587
el.addEventListener('focus', () => {
76-
addTooltipElement(tooltip, el, popperOptions)
88+
addTooltipElement(el, tooltip, popperOptions, uID)
7789
})
7890
el.addEventListener('blur', () => {
79-
removeTooltipElement(tooltip)
91+
removeTooltipElement(el, tooltip)
8092
})
8193
}
8294

8395
if (trigger.includes('hover')) {
8496
el.addEventListener('mouseenter', () => {
85-
addTooltipElement(tooltip, el, popperOptions)
97+
addTooltipElement(el, tooltip, popperOptions, uID)
8698
})
8799
el.addEventListener('mouseleave', () => {
88-
removeTooltipElement(tooltip)
100+
removeTooltipElement(el, tooltip)
89101
})
90102
}
91103
},

packages/docs/components/tooltip.md

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -56,45 +56,45 @@ Hover over the buttons below to see the four tooltips directions: top, right, bo
5656

5757
::: demo
5858
<CTooltip content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="top">
59-
<template #toggler="{ on }">
60-
<CButton color="secondary" v-on="on">Tooltip on top</CButton>
59+
<template #toggler="{ id, on }">
60+
<CButton color="secondary" :aria-describedby="id" v-on="on">Tooltip on top</CButton>
6161
</template>
6262
</CTooltip>
6363
<CTooltip content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="right">
64-
<template #toggler="{ on }">
65-
<CButton color="secondary" v-on="on">Tooltip on right</CButton>
64+
<template #toggler="{ id, on }">
65+
<CButton color="secondary" :aria-describedby="id" v-on="on">Tooltip on right</CButton>
6666
</template>
6767
</CTooltip>
6868
<CTooltip content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="bottom">
69-
<template #toggler="{ on }">
70-
<CButton color="secondary" v-on="on">Tooltip on bottom</CButton>
69+
<template #toggler="{ id, on }">
70+
<CButton color="secondary" :aria-describedby="id" v-on="on">Tooltip on bottom</CButton>
7171
</template>
7272
</CTooltip>
7373
<CTooltip content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="left">
74-
<template #toggler="{ on }">
75-
<CButton color="secondary" v-on="on">Tooltip on left</CButton>
74+
<template #toggler="{ id, on }">
75+
<CButton color="secondary" :aria-describedby="id" v-on="on">Tooltip on left</CButton>
7676
</template>
7777
</CTooltip>
7878
:::
7979
```vue
8080
<CTooltip content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="top">
81-
<template #toggler="{ on }">
82-
<CButton color="secondary" v-on="on">Tooltip on top</CButton>
81+
<template #toggler="{ id, on }">
82+
<CButton color="secondary" :aria-describedby="id" v-on="on">Tooltip on top</CButton>
8383
</template>
8484
</CTooltip>
8585
<CTooltip content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="right">
86-
<template #toggler="{ on }">
87-
<CButton color="secondary" v-on="on">Tooltip on right</CButton>
86+
<template #toggler="{ id, on }">
87+
<CButton color="secondary" :aria-describedby="id" v-on="on">Tooltip on right</CButton>
8888
</template>
8989
</CTooltip>
9090
<CTooltip content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="bottom">
91-
<template #toggler="{ on }">
92-
<CButton color="secondary" v-on="on">Tooltip on bottom</CButton>
91+
<template #toggler="{ id, on }">
92+
<CButton color="secondary" :aria-describedby="id" v-on="on">Tooltip on bottom</CButton>
9393
</template>
9494
</CTooltip>
9595
<CTooltip content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="left">
96-
<template #toggler="{ on }">
97-
<CButton color="secondary" v-on="on">Tooltip on left</CButton>
96+
<template #toggler="{ id, on }">
97+
<CButton color="secondary" :aria-describedby="id" v-on="on">Tooltip on left</CButton>
9898
</template>
9999
</CTooltip>
100100
```
@@ -124,8 +124,8 @@ You can customize the appearance of tooltips using [CSS variables](#css-variable
124124
placement="top"
125125
:style="customTooltipStyle"
126126
>
127-
<template #toggler="{ on }">
128-
<CButton color="secondary" v-on="on">Custom popover</CButton>
127+
<template #toggler="{ id, on }">
128+
<CButton color="secondary" :aria-describedby="id" v-on="on">Custom popover</CButton>
129129
</template>
130130
</CTooltip>
131131
:::
@@ -136,8 +136,8 @@ You can customize the appearance of tooltips using [CSS variables](#css-variable
136136
placement="top"
137137
:style="customTooltipStyle"
138138
>
139-
<template #toggler="{ on }">
140-
<CButton color="secondary" v-on="on">Custom popover</CButton>
139+
<template #toggler="{ id, on }">
140+
<CButton color="secondary" :aria-describedby="id" v-on="on">Custom popover</CButton>
141141
</template>
142142
</CTooltip>
143143
</template>
@@ -162,17 +162,17 @@ Elements with the disabled attribute aren’t interactive, meaning users cannot
162162

163163
:::demo
164164
<CTooltip content="Disabled tooltip">
165-
<template #toggler="{ on }">
166-
<span class="d-inline-block" :tabindex="0" v-on="on">
165+
<template #toggler="{ id, on }">
166+
<span class="d-inline-block" :tabindex="0" :aria-describedby="id" v-on="on">
167167
<CButton color="primary" disabled>Disabled button</CButton>
168168
</span>
169169
</template>
170170
</CTooltip>
171171
:::
172172
```vue
173173
<CTooltip content="Disabled tooltip">
174-
<template #toggler="{ on }">
175-
<span class="d-inline-block" :tabindex="0" v-on="on">
174+
<template #toggler="{ id, on }">
175+
<span class="d-inline-block" :tabindex="0" :aria-describedby="id" v-on="on">
176176
<CButton color="primary" disabled>Disabled button</CButton>
177177
</span>
178178
</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