Accordion
A collapsible component that displays content in a vertical stack.
import { ChevronDownIcon } from 'lucide-react'
import { Accordion } from '~/components/ui/accordion'
export const Demo = (props: Accordion.RootProps) => {
const items = ['React', 'Solid', 'Svelte', 'Vue']
return (
<Accordion.Root defaultValue={['React']} multiple {...props}>
{items.map((item, id) => (
<Accordion.Item key={id} value={item} disabled={item === 'Svelte'}>
<Accordion.ItemTrigger>
{item}
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
Pudding donut gummies chupa chups oat cake marzipan biscuit tart. Dessert macaroon ice
cream bonbon jelly. Jelly topping tiramisu halvah lollipop.
</Accordion.ItemContent>
</Accordion.Item>
))}
</Accordion.Root>
)
}
import { ChevronDownIcon } from 'lucide-solid'
import { For } from 'solid-js'
import { Accordion } from '~/components/ui/accordion'
export const Demo = (props: Accordion.RootProps) => {
const items = ['React', 'Solid', 'Svelte', 'Vue']
return (
<Accordion.Root defaultValue={['React']} multiple {...props}>
<For each={items}>
{(item) => (
<Accordion.Item value={item} disabled={item === 'Svelte'}>
<Accordion.ItemTrigger>
{item}
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
Pudding donut gummies chupa chups oat cake marzipan biscuit tart. Dessert macaroon ice
cream bonbon jelly. Jelly topping tiramisu halvah lollipop.
</Accordion.ItemContent>
</Accordion.Item>
)}
</For>
</Accordion.Root>
)
}
Usage
import { Accordion } from '~/components/ui/accordion'
Installation
npx @park-ui/cli components add accordion
1
Add Styled Primitive
Copy the code snippet below into ~/components/ui/styled/accordion.tsx
'use client'
import type { Assign } from '@ark-ui/react'
import { Accordion } from '@ark-ui/react/accordion'
import { type AccordionVariantProps, accordion } from 'styled-system/recipes'
import type { ComponentProps, HTMLStyledProps } from 'styled-system/types'
import { createStyleContext } from './utils/create-style-context'
const { withProvider, withContext } = createStyleContext(accordion)
export type RootProviderProps = ComponentProps<typeof RootProvider>
export const RootProvider = withProvider<
HTMLDivElement,
Assign<Assign<HTMLStyledProps<'div'>, Accordion.RootProviderBaseProps>, AccordionVariantProps>
>(Accordion.RootProvider, 'root')
export type RootProps = ComponentProps<typeof Root>
export const Root = withProvider<
HTMLDivElement,
Assign<Assign<HTMLStyledProps<'div'>, Accordion.RootBaseProps>, AccordionVariantProps>
>(Accordion.Root, 'root')
export const ItemContent = withContext<
HTMLDivElement,
Assign<HTMLStyledProps<'div'>, Accordion.ItemContentBaseProps>
>(Accordion.ItemContent, 'itemContent')
export const ItemIndicator = withContext<
HTMLDivElement,
Assign<HTMLStyledProps<'div'>, Accordion.ItemIndicatorBaseProps>
>(Accordion.ItemIndicator, 'itemIndicator')
export const Item = withContext<
HTMLDivElement,
Assign<HTMLStyledProps<'div'>, Accordion.ItemBaseProps>
>(Accordion.Item, 'item')
export const ItemTrigger = withContext<
HTMLButtonElement,
Assign<HTMLStyledProps<'button'>, Accordion.ItemTriggerBaseProps>
>(Accordion.ItemTrigger, 'itemTrigger')
export {
AccordionContext as Context,
AccordionItemContext as ItemContext,
} from '@ark-ui/react/accordion'
export type {
AccordionFocusChangeDetails as FocusChangeDetails,
AccordionValueChangeDetails as ValueChangeDetails,
} from '@ark-ui/react/accordion'
import { Accordion, type Assign } from '@ark-ui/solid'
import type { ComponentProps } from 'solid-js'
import { type AccordionVariantProps, accordion } from 'styled-system/recipes'
import type { HTMLStyledProps } from 'styled-system/types'
import { createStyleContext } from './utils/create-style-context'
const { withProvider, withContext } = createStyleContext(accordion)
export type RootProviderProps = ComponentProps<typeof RootProvider>
export const RootProvider = withProvider<
Assign<Assign<HTMLStyledProps<'div'>, Accordion.RootProviderBaseProps>, AccordionVariantProps>
>(Accordion.RootProvider, 'root')
export type RootProps = ComponentProps<typeof Root>
export const Root = withProvider<
Assign<Assign<HTMLStyledProps<'div'>, Accordion.RootBaseProps>, AccordionVariantProps>
>(Accordion.Root, 'root')
export const ItemContent = withContext<
Assign<HTMLStyledProps<'div'>, Accordion.ItemContentBaseProps>
>(Accordion.ItemContent, 'itemContent')
export const ItemIndicator = withContext<
Assign<HTMLStyledProps<'div'>, Accordion.ItemIndicatorBaseProps>
>(Accordion.ItemIndicator, 'itemIndicator')
export const Item = withContext<Assign<HTMLStyledProps<'div'>, Accordion.ItemBaseProps>>(
Accordion.Item,
'item',
)
export const ItemTrigger = withContext<
Assign<HTMLStyledProps<'button'>, Accordion.ItemTriggerBaseProps>
>(Accordion.ItemTrigger, 'itemTrigger')
export { AccordionContext as Context, AccordionItemContext as ItemContext } from '@ark-ui/solid'
export type {
AccordionFocusChangeDetails as FocusChangeDetails,
AccordionValueChangeDetails as ValueChangeDetails,
} from '@ark-ui/solid'
No snippet found
2
Add Re-Export
To improve the developer experience, re-export the styled primitives in~/components/ui/accordion.tsx
.
export * as Accordion from './styled/accordion'
export * as Accordion from './styled/accordion'
3
Integrate Recipe
If you're not using @park-ui/preset
, add the following recipe to yourpanda.config.ts
:
import { accordionAnatomy } from '@ark-ui/anatomy'
import { defineSlotRecipe } from '@pandacss/dev'
export const accordion = defineSlotRecipe({
className: 'accordion',
slots: accordionAnatomy.keys(),
base: {
root: {
divideY: '1px',
width: 'full',
borderTopWidth: '1px',
borderBottomWidth: '1px',
},
itemTrigger: {
alignItems: 'center',
color: 'fg.default',
cursor: 'pointer',
display: 'flex',
fontWeight: 'semibold',
gap: '3',
justifyContent: 'space-between',
textStyle: 'lg',
textAlign: 'left',
width: 'full',
_disabled: {
color: 'fg.disabled',
cursor: 'not-allowed',
},
},
itemIndicator: {
color: 'fg.muted',
transformOrigin: 'center',
transitionDuration: 'normal',
transitionProperty: 'transform',
transitionTimingFunction: 'default',
_open: {
transform: 'rotate(-180deg)',
},
},
itemContent: {
color: 'fg.muted',
overflow: 'hidden',
transitionProperty: 'padding-bottom',
transitionDuration: 'normal',
transitionTimingFunction: 'default',
_open: {
animation: 'collapse-in',
},
_closed: {
animation: 'collapse-out',
},
},
},
defaultVariants: {
size: 'md',
},
variants: {
size: {
md: {
itemTrigger: {
py: '4',
},
itemContent: {
pb: '6',
pr: '8',
_closed: {
pb: '0',
},
},
},
},
},
})