Skip to content

Commit 7b9da86

Browse files
committed
docs(toggle-group): add with-tooltip example composing Item and Tooltip.Trigger
Compose ToggleGroup.Item with Tooltip.Trigger via asChild, giving both a matching custom id through ids.item/ids.trigger so they share one element and tab stop while keeping roving focus and tooltip positioning working. Addresses #3934.
1 parent 1af4b0a commit 7b9da86

10 files changed

Lines changed: 195 additions & 0 deletions

File tree

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { Portal } from '@ark-ui/react/portal'
2+
import { ToggleGroup } from '@ark-ui/react/toggle-group'
3+
import { Tooltip, useTooltip } from '@ark-ui/react/tooltip'
4+
import { BoldIcon, ItalicIcon, UnderlineIcon } from 'lucide-react'
5+
import styles from 'styles/toggle-group.module.css'
6+
import tooltipStyles from 'styles/tooltip.module.css'
7+
8+
const items = [
9+
{ value: 'bold', label: 'Bold', icon: <BoldIcon /> },
10+
{ value: 'italic', label: 'Italic', icon: <ItalicIcon /> },
11+
{ value: 'underline', label: 'Underline', icon: <UnderlineIcon /> },
12+
]
13+
14+
const getTriggerId = (value?: string) => `toggle-item:${value}`
15+
16+
export const WithTooltip = () => {
17+
const tooltip = useTooltip({ ids: { trigger: getTriggerId } })
18+
19+
return (
20+
<Tooltip.RootProvider value={tooltip}>
21+
<ToggleGroup.Root defaultValue={['bold']} ids={{ item: getTriggerId }} className={styles.Root}>
22+
{items.map((item) => (
23+
<ToggleGroup.Item key={item.value} value={item.value} aria-label={item.label} className={styles.Item} asChild>
24+
<Tooltip.Trigger value={item.value}>{item.icon}</Tooltip.Trigger>
25+
</ToggleGroup.Item>
26+
))}
27+
</ToggleGroup.Root>
28+
<Portal>
29+
<Tooltip.Positioner>
30+
<Tooltip.Content className={tooltipStyles.Content}>
31+
{items.find((item) => item.value === tooltip.triggerValue)?.label}
32+
</Tooltip.Content>
33+
</Tooltip.Positioner>
34+
</Portal>
35+
</Tooltip.RootProvider>
36+
)
37+
}

packages/react/src/components/toggle-group/toggle-group.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ export { Basic } from './examples/basic.tsx'
1010
export { Controlled } from './examples/controlled.tsx'
1111
export { Multiple } from './examples/multiple.tsx'
1212
export { RootProvider } from './examples/root-provider.tsx'
13+
export { WithTooltip } from './examples/with-tooltip.tsx'
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { ToggleGroup } from '@ark-ui/solid/toggle-group'
2+
import { Tooltip, useTooltip } from '@ark-ui/solid/tooltip'
3+
import { BoldIcon, ItalicIcon, UnderlineIcon } from 'lucide-solid'
4+
import { For } from 'solid-js'
5+
import { Portal } from 'solid-js/web'
6+
import styles from 'styles/toggle-group.module.css'
7+
import tooltipStyles from 'styles/tooltip.module.css'
8+
9+
const items = [
10+
{ value: 'bold', label: 'Bold', icon: BoldIcon },
11+
{ value: 'italic', label: 'Italic', icon: ItalicIcon },
12+
{ value: 'underline', label: 'Underline', icon: UnderlineIcon },
13+
]
14+
15+
const getTriggerId = (value?: string) => `toggle-item:${value}`
16+
17+
export const WithTooltip = () => {
18+
const tooltip = useTooltip({ ids: { trigger: getTriggerId } })
19+
20+
return (
21+
<Tooltip.RootProvider value={tooltip}>
22+
<ToggleGroup.Root defaultValue={['bold']} ids={{ item: getTriggerId }} class={styles.Root}>
23+
<For each={items}>
24+
{(item) => (
25+
<ToggleGroup.Item
26+
value={item.value}
27+
aria-label={item.label}
28+
class={styles.Item}
29+
asChild={(itemProps) => (
30+
<Tooltip.Trigger value={item.value} {...itemProps()}>
31+
<item.icon />
32+
</Tooltip.Trigger>
33+
)}
34+
/>
35+
)}
36+
</For>
37+
</ToggleGroup.Root>
38+
<Portal>
39+
<Tooltip.Positioner>
40+
<Tooltip.Content class={tooltipStyles.Content}>
41+
{items.find((item) => item.value === tooltip().triggerValue)?.label}
42+
</Tooltip.Content>
43+
</Tooltip.Positioner>
44+
</Portal>
45+
</Tooltip.RootProvider>
46+
)
47+
}

packages/solid/src/components/toggle-group/toggle-group.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ export { Basic } from './examples/basic.tsx'
1010
export { Controlled } from './examples/controlled.tsx'
1111
export { Multiple } from './examples/multiple.tsx'
1212
export { RootProvider } from './examples/root-provider.tsx'
13+
export { WithTooltip } from './examples/with-tooltip.tsx'
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<script lang="ts">
2+
import { Portal } from '@ark-ui/svelte/portal'
3+
import { ToggleGroup } from '@ark-ui/svelte/toggle-group'
4+
import { Tooltip, useTooltip } from '@ark-ui/svelte/tooltip'
5+
import BoldIcon from 'lucide-svelte/icons/bold'
6+
import ItalicIcon from 'lucide-svelte/icons/italic'
7+
import UnderlineIcon from 'lucide-svelte/icons/underline'
8+
import styles from 'styles/toggle-group.module.css'
9+
import tooltipStyles from 'styles/tooltip.module.css'
10+
11+
const items = [
12+
{ value: 'bold', label: 'Bold', icon: BoldIcon },
13+
{ value: 'italic', label: 'Italic', icon: ItalicIcon },
14+
{ value: 'underline', label: 'Underline', icon: UnderlineIcon },
15+
]
16+
17+
const getTriggerId = (value?: string) => `toggle-item:${value}`
18+
19+
const id = $props.id()
20+
const tooltip = useTooltip({ id, ids: { trigger: getTriggerId } })
21+
</script>
22+
23+
<Tooltip.RootProvider value={tooltip}>
24+
<ToggleGroup.Root defaultValue={['bold']} ids={{ item: getTriggerId }} class={styles.Root}>
25+
{#each items as item (item.value)}
26+
<ToggleGroup.Item value={item.value} aria-label={item.label} class={styles.Item}>
27+
{#snippet asChild(itemProps)}
28+
<Tooltip.Trigger value={item.value} {...itemProps()}>
29+
<item.icon />
30+
</Tooltip.Trigger>
31+
{/snippet}
32+
</ToggleGroup.Item>
33+
{/each}
34+
</ToggleGroup.Root>
35+
<Portal>
36+
<Tooltip.Positioner>
37+
<Tooltip.Content class={tooltipStyles.Content}>
38+
{items.find((item) => item.value === tooltip().triggerValue)?.label}
39+
</Tooltip.Content>
40+
</Tooltip.Positioner>
41+
</Portal>
42+
</Tooltip.RootProvider>

packages/svelte/src/lib/components/toggle-group/toggle-group.stories.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import BasicExample from './examples/basic.svelte'
33
import ControlledExample from './examples/controlled.svelte'
44
import MultipleExample from './examples/multiple.svelte'
55
import RootProviderExample from './examples/root-provider.svelte'
6+
import WithTooltipExample from './examples/with-tooltip.svelte'
67

78
const meta: Meta = {
89
title: 'Components / Toggle Group',
@@ -33,3 +34,9 @@ export const RootProvider = {
3334
Component: RootProviderExample,
3435
}),
3536
}
37+
38+
export const WithTooltip = {
39+
render: () => ({
40+
Component: WithTooltipExample,
41+
}),
42+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<script setup lang="ts">
2+
import { ToggleGroup } from '@ark-ui/vue/toggle-group'
3+
import { Tooltip, useTooltip } from '@ark-ui/vue/tooltip'
4+
import { BoldIcon, ItalicIcon, UnderlineIcon } from 'lucide-vue-next'
5+
import { computed } from 'vue'
6+
import styles from 'styles/toggle-group.module.css'
7+
import tooltipStyles from 'styles/tooltip.module.css'
8+
9+
const items = [
10+
{ value: 'bold', label: 'Bold', icon: BoldIcon },
11+
{ value: 'italic', label: 'Italic', icon: ItalicIcon },
12+
{ value: 'underline', label: 'Underline', icon: UnderlineIcon },
13+
]
14+
15+
const getTriggerId = (value?: string) => `toggle-item:${value}`
16+
17+
const tooltip = useTooltip({ ids: { trigger: getTriggerId } })
18+
const activeLabel = computed(() => items.find((item) => item.value === tooltip.value.triggerValue)?.label)
19+
</script>
20+
21+
<template>
22+
<Tooltip.RootProvider :value="tooltip">
23+
<ToggleGroup.Root :defaultValue="['bold']" :ids="{ item: getTriggerId }" :class="styles.Root">
24+
<ToggleGroup.Item
25+
v-for="item in items"
26+
:key="item.value"
27+
:value="item.value"
28+
:aria-label="item.label"
29+
:class="styles.Item"
30+
asChild
31+
>
32+
<Tooltip.Trigger :value="item.value">
33+
<component :is="item.icon" />
34+
</Tooltip.Trigger>
35+
</ToggleGroup.Item>
36+
</ToggleGroup.Root>
37+
<Teleport to="body">
38+
<Tooltip.Positioner>
39+
<Tooltip.Content :class="tooltipStyles.Content">{{ activeLabel }}</Tooltip.Content>
40+
</Tooltip.Positioner>
41+
</Teleport>
42+
</Tooltip.RootProvider>
43+
</template>

packages/vue/src/components/toggle-group/toggle-group.stories.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import BasicExample from './examples/basic.vue'
44
import ControlledExample from './examples/controlled.vue'
55
import MultipleExample from './examples/multiple.vue'
66
import RootProviderExample from './examples/root-provider.vue'
7+
import WithTooltipExample from './examples/with-tooltip.vue'
78

89
const meta: Meta = {
910
title: 'Components / Toggle Group',
@@ -38,3 +39,10 @@ export const RootProvider = {
3839
template: '<Component />',
3940
}),
4041
}
42+
43+
export const WithTooltip = {
44+
render: () => ({
45+
components: { Component: WithTooltipExample },
46+
template: '<Component />',
47+
}),
48+
}

website/src/content/pages/components/toggle-group.mdx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ Demonstrates how to enable `multiple` selection within the group.
3939

4040
<Example id="multiple" />
4141

42+
### With Tooltip
43+
44+
Pair an item with a `Tooltip.Trigger` via `asChild`, matching their ids with `ids.item` and `ids.trigger` so they share
45+
one element and tab stop.
46+
47+
<Example id="with-tooltip" />
48+
4249
## API Reference
4350

4451
### Props

website/src/lib/example-registry.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,7 @@ import * as ToggleGroup_Basic from '@examples/toggle-group/examples/basic'
548548
import * as ToggleGroup_Controlled from '@examples/toggle-group/examples/controlled'
549549
import * as ToggleGroup_Multiple from '@examples/toggle-group/examples/multiple'
550550
import * as ToggleGroup_RootProvider from '@examples/toggle-group/examples/root-provider'
551+
import * as ToggleGroup_WithTooltip from '@examples/toggle-group/examples/with-tooltip'
551552
import * as Toggle_Basic from '@examples/toggle/examples/basic'
552553
import * as Toggle_Context from '@examples/toggle/examples/context'
553554
import * as Toggle_Controlled from '@examples/toggle/examples/controlled'
@@ -1147,6 +1148,7 @@ const exampleModules: Record<string, ExampleModule> = {
11471148
'toggle-group/controlled': ToggleGroup_Controlled,
11481149
'toggle-group/multiple': ToggleGroup_Multiple,
11491150
'toggle-group/root-provider': ToggleGroup_RootProvider,
1151+
'toggle-group/with-tooltip': ToggleGroup_WithTooltip,
11501152
'toggle/basic': Toggle_Basic,
11511153
'toggle/context': Toggle_Context,
11521154
'toggle/controlled': Toggle_Controlled,

0 commit comments

Comments
 (0)