Toggle Group
A set of two-state buttons that can be toggled on or off.
outline
ghost
import {
AlignCenterIcon,
AlignJustifyIcon,
AlignLeftIcon,
AlignRightIcon,
BoldIcon,
ItalicIcon,
UnderlineIcon,
} from 'lucide-react'
import { Stack } from 'styled-system/jsx'
import { ToggleGroup } from '~/components/ui/toggle-group'
export const Demo = (props: ToggleGroup.RootProps) => {
return (
<Stack
direction={props.orientation === 'horizontal' ? 'row' : 'column'}
gap="3"
borderRadius="l3"
borderWidth={props.variant === 'ghost' ? '1px' : '0'}
p={props.variant === 'ghost' ? '1' : '0'}
>
<ToggleGroup.Root multiple {...props}>
<ToggleGroup.Item value="bold" aria-label="Toggle Bold">
<BoldIcon />
</ToggleGroup.Item>
<ToggleGroup.Item value="italic" aria-label="Toggle Italic">
<ItalicIcon />
</ToggleGroup.Item>
<ToggleGroup.Item value="underline" aria-label="Toggle Underline">
<UnderlineIcon />
</ToggleGroup.Item>
</ToggleGroup.Root>
<ToggleGroup.Root defaultValue={['left']} {...props}>
<ToggleGroup.Item value="left" aria-label="Align Left">
<AlignLeftIcon />
</ToggleGroup.Item>
<ToggleGroup.Item value="center" aria-label="Align Center">
<AlignCenterIcon />
</ToggleGroup.Item>
<ToggleGroup.Item value="right" aria-label="Align Right">
<AlignRightIcon />
</ToggleGroup.Item>
<ToggleGroup.Item value="justify" aria-label="Align Justify">
<AlignJustifyIcon />
</ToggleGroup.Item>
</ToggleGroup.Root>
</Stack>
)
}
import {
AlignCenterIcon,
AlignJustifyIcon,
AlignLeftIcon,
AlignRightIcon,
BoldIcon,
ItalicIcon,
UnderlineIcon,
} from 'lucide-solid'
import { Stack } from 'styled-system/jsx'
import { ToggleGroup } from '~/components/ui/toggle-group'
export const Demo = (props: ToggleGroup.RootProps) => {
return (
<Stack
direction={props.orientation === 'horizontal' ? 'row' : 'column'}
gap="3"
borderRadius="l3"
borderWidth={props.variant === 'ghost' ? '1px' : '0'}
p={props.variant === 'ghost' ? '1' : '0'}
>
<ToggleGroup.Root multiple {...props}>
<ToggleGroup.Item value="bold" aria-label="Toggle Bold">
<BoldIcon />
</ToggleGroup.Item>
<ToggleGroup.Item value="italic" aria-label="Toggle Italic">
<ItalicIcon />
</ToggleGroup.Item>
<ToggleGroup.Item value="underline" aria-label="Toggle Underline">
<UnderlineIcon />
</ToggleGroup.Item>
</ToggleGroup.Root>
<ToggleGroup.Root defaultValue={['left']} {...props}>
<ToggleGroup.Item value="left" aria-label="Align Left">
<AlignLeftIcon />
</ToggleGroup.Item>
<ToggleGroup.Item value="center" aria-label="Align Center">
<AlignCenterIcon />
</ToggleGroup.Item>
<ToggleGroup.Item value="right" aria-label="Align Right">
<AlignRightIcon />
</ToggleGroup.Item>
<ToggleGroup.Item value="justify" aria-label="Align Justify">
<AlignJustifyIcon />
</ToggleGroup.Item>
</ToggleGroup.Root>
</Stack>
)
}
Usage
import { ToggleGroup } from '~/components/ui/toggle-group'
Installation
npx @park-ui/cli components add toggle-group
1
Add Styled Primitive
Copy the code snippet below into ~/components/ui/styled/toggle-group.tsx
'use client'
import type { Assign } from '@ark-ui/react'
import { ToggleGroup } from '@ark-ui/react/toggle-group'
import { type ToggleGroupVariantProps, toggleGroup } from 'styled-system/recipes'
import type { ComponentProps, HTMLStyledProps } from 'styled-system/types'
import { createStyleContext } from './utils/create-style-context'
const { withProvider, withContext } = createStyleContext(toggleGroup)
export type RootProviderProps = ComponentProps<typeof RootProvider>
export const RootProvider = withProvider<
HTMLDivElement,
Assign<Assign<HTMLStyledProps<'div'>, ToggleGroup.RootProviderBaseProps>, ToggleGroupVariantProps>
>(ToggleGroup.RootProvider, 'root')
export type RootProps = ComponentProps<typeof Root>
export const Root = withProvider<
HTMLDivElement,
Assign<Assign<HTMLStyledProps<'div'>, ToggleGroup.RootBaseProps>, ToggleGroupVariantProps>
>(ToggleGroup.Root, 'root')
export const Item = withContext<
HTMLButtonElement,
Assign<HTMLStyledProps<'button'>, ToggleGroup.ItemBaseProps>
>(ToggleGroup.Item, 'item')
export { ToggleGroupContext as Context } from '@ark-ui/react/toggle-group'
import { type Assign, ToggleGroup } from '@ark-ui/solid'
import type { ComponentProps } from 'solid-js'
import { type ToggleGroupVariantProps, toggleGroup } from 'styled-system/recipes'
import type { HTMLStyledProps } from 'styled-system/types'
import { createStyleContext } from './utils/create-style-context'
const { withProvider, withContext } = createStyleContext(toggleGroup)
export type RootProviderProps = ComponentProps<typeof RootProvider>
export const RootProvider = withProvider<
Assign<Assign<HTMLStyledProps<'div'>, ToggleGroup.RootProviderBaseProps>, ToggleGroupVariantProps>
>(ToggleGroup.RootProvider, 'root')
export type RootProps = ComponentProps<typeof Root>
export const Root = withProvider<
Assign<Assign<HTMLStyledProps<'div'>, ToggleGroup.RootBaseProps>, ToggleGroupVariantProps>
>(ToggleGroup.Root, 'root')
export const Item = withContext<Assign<HTMLStyledProps<'button'>, ToggleGroup.ItemBaseProps>>(
ToggleGroup.Item,
'item',
)
export { ToggleGroupContext as Context } from '@ark-ui/solid'
No snippet found
2
Add Re-Export
To improve the developer experience, re-export the styled primitives in~/components/ui/toggle-group.tsx
.
export * as ToggleGroup from './styled/toggle-group'
export * as ToggleGroup from './styled/toggle-group'
3
Integrate Recipe
If you're not using @park-ui/preset
, add the following recipe to yourpanda.config.ts
:
import { toggleGroupAnatomy } from '@ark-ui/anatomy'
import { defineSlotRecipe } from '@pandacss/dev'
export const toggleGroup = defineSlotRecipe({
className: 'toggleGroup',
slots: toggleGroupAnatomy.keys(),
base: {
root: {
display: 'flex',
overflow: 'hidden',
position: 'relative',
_vertical: {
flexDirection: 'column',
},
},
item: {
alignItems: 'center',
appearance: 'none',
cursor: 'pointer',
color: 'fg.subtle',
display: 'inline-flex',
fontWeight: 'semibold',
minWidth: '0',
justifyContent: 'center',
outline: 'none',
position: 'relative',
transitionDuration: 'normal',
transitionProperty: 'background, border-color, color, box-shadow',
transitionTimingFunction: 'default',
userSelect: 'none',
verticalAlign: 'middle',
whiteSpace: 'nowrap',
_on: {
background: 'gray.a3',
color: 'fg.default',
_hover: {
background: 'gray.a3',
},
},
_hover: {
background: 'gray.a2',
},
_disabled: {
borderColor: 'border.disabled',
color: 'fg.disabled',
cursor: 'not-allowed',
_hover: {
background: 'transparent',
borderColor: 'border.disabled',
color: 'fg.disabled',
},
},
},
},
defaultVariants: {
size: 'md',
variant: 'outline',
},
variants: {
variant: {
outline: {
root: {
borderWidth: '1px',
borderRadius: 'l2',
borderColor: 'border.default',
_horizontal: {
divideX: '1px',
},
_vertical: {
divideY: '1px',
},
},
item: {
borderColor: 'border.default',
_focusVisible: {
color: 'fg.default',
background: 'gray.a3',
},
},
},
ghost: {
root: {
gap: '1',
},
item: {
borderRadius: 'l2',
_focusVisible: {
outlineOffset: '2px',
outline: '2px solid',
outlineColor: 'border.outline',
},
},
},
},
size: {
sm: {
item: {
h: '9',
minW: '9',
textStyle: 'sm',
gap: '2',
'& svg': {
width: '4.5',
height: '4.5',
},
},
},
md: {
item: {
h: '10',
minW: '10',
textStyle: 'sm',
gap: '2',
'& svg': {
width: '5',
height: '5',
},
},
},
lg: {
item: {
h: '11',
minW: '11',
textStyle: 'md',
gap: '2',
'& svg': {
width: '5',
height: '5',
},
},
},
},
},
})