Accordion
A component that consists of multiple collapsible sections.
import Accordion from 'corvu/accordion'
import type { VoidComponent } from 'solid-js'
const AccordionExample: VoidComponent = () => {
return (
<div class="my-auto w-full max-w-[250px] overflow-hidden rounded-lg @xl:max-w-[400px]">
<Accordion.Root collapseBehavior="hide">
<Accordion.Item>
<h3>
<Accordion.Trigger class="w-full border-b border-corvu-200 bg-corvu-50 px-4 py-3 text-left font-medium text-corvu-dark transition-all duration-100 hover:bg-corvu-100 focus-visible:bg-corvu-200 focus-visible:outline-none">
What is corvu?
</Accordion.Trigger>
</h3>
<Accordion.Content class="overflow-hidden border-b border-corvu-200 bg-corvu-100 corvu-expanded:animate-expand corvu-collapsed:animate-collapse">
<div class="px-4 py-2">
A collection of unstyled, customizable UI primitives for SolidJS.
</div>
</Accordion.Content>
</Accordion.Item>
<Accordion.Item>
<h3>
<Accordion.Trigger class="w-full border-b border-corvu-200 bg-corvu-50 px-4 py-3 text-left font-medium text-corvu-dark transition-all duration-100 hover:bg-corvu-100 focus-visible:bg-corvu-200 focus-visible:outline-none">
Is it accessible?
</Accordion.Trigger>
</h3>
<Accordion.Content class="overflow-hidden border-b border-corvu-200 bg-corvu-100 corvu-expanded:animate-expand corvu-collapsed:animate-collapse">
<div class="px-4 py-2">
It has full keyboard support and adheres to the WAI-ARIA pattern
for accordions.
</div>
</Accordion.Content>
</Accordion.Item>
<Accordion.Item>
<h3>
<Accordion.Trigger class="w-full border-b border-corvu-200 bg-corvu-50 px-4 py-3 text-left font-medium text-corvu-dark transition-all duration-100 hover:bg-corvu-100 focus-visible:bg-corvu-200 focus-visible:outline-none">
Can I customize it?
</Accordion.Trigger>
</h3>
<Accordion.Content class="overflow-hidden border-b border-corvu-200 bg-corvu-100 corvu-expanded:animate-expand corvu-collapsed:animate-collapse">
<div class="px-4 py-2">
Yes, check out the API reference at the bottom for all options.
</div>
</Accordion.Content>
</Accordion.Item>
</Accordion.Root>
</div>
)
}
export default AccordionExample
/** @type {import('tailwindcss').Config} */
export default {
content: ['./src/**/*.{ts,tsx}'],
theme: {
extend: {
colors: {
corvu: {
50: '#f2f0fe',
100: '#e6e2fd',
200: '#d4cbfb',
light: '#D4C0FF',
300: '#bcacf6',
400: '#a888f1',
500: '#9a6de9',
600: '#8f50dc',
700: '#7e41c3',
accent: '#7250AE',
800: '#63359c',
900: '#52317d',
dark: '#180f23',
1000: '#0C0812',
},
},
animation: {
expand: 'expand 200ms linear',
collapse: 'collapse 200ms linear',
},
keyframes: {
expand: {
'0%': {
height: '0px',
},
'100%': {
height: 'var(--corvu-disclosure-content-height)',
},
},
collapse: {
'0%': {
height: 'var(--corvu-disclosure-content-height)',
},
'100%': {
height: '0px',
},
},
},
},
},
plugins: [require('@corvu/tailwind')],
}
import Accordion from 'corvu/accordion'
import type { VoidComponent } from 'solid-js'
const AccordionExample: VoidComponent = () => {
return (
<div class="wrapper">
<Accordion.Root collapseBehavior="hide">
<Accordion.Item>
<h3>
<Accordion.Trigger>What is corvu?</Accordion.Trigger>
</h3>
<Accordion.Content>
<div class="content_wrapper">
A collection of unstyled, customizable UI primitives for SolidJS.
</div>
</Accordion.Content>
</Accordion.Item>
<Accordion.Item>
<h3>
<Accordion.Trigger>Is it accessible?</Accordion.Trigger>
</h3>
<Accordion.Content>
<div class="content_wrapper">
It has full keyboard support and adheres to the WAI-ARIA pattern
for accordions.
</div>
</Accordion.Content>
</Accordion.Item>
<Accordion.Item>
<h3>
<Accordion.Trigger>Can I customize it?</Accordion.Trigger>
</h3>
<Accordion.Content>
<div class="content_wrapper">
Yes, check out the API reference at the bottom for all options.
</div>
</Accordion.Content>
</Accordion.Item>
</Accordion.Root>
</div>
)
}
export default AccordionExample
.wrapper {
margin-top: auto;
margin-bottom: auto;
width: 100%;
max-width: 250px;
overflow: hidden;
border-radius: 0.5rem;
}
[data-corvu-accordion-trigger] {
width: 100%;
border-bottom-width: 1px;
border-color: rgb(212 203 251);
background-color: rgb(242 240 254);
padding-left: 1rem;
padding-right: 1rem;
padding-top: 0.75rem;
padding-bottom: 0.75rem;
text-align: left;
font-weight: 500;
color: rgb(24 15 35);
transition-property: all;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
transition-duration: 100ms;
}
[data-corvu-accordion-trigger]:hover {
background-color: rgb(230 226 253);
}
[data-corvu-accordion-trigger]:focus-visible {
outline: 2px solid transparent;
outline-offset: 2px;
background-color: rgb(212 203 251);
}
[data-corvu-accordion-content] {
border-bottom-width: 1px;
overflow: hidden;
border-color: rgb(212 203 251);
background-color: rgb(230 226 253);
}
[data-corvu-accordion-content][data-collapsed] {
animation: collapse 200ms linear;
}
[data-corvu-accordion-content][data-expanded] {
animation: expand 200ms linear;
}
@keyframes expand {
0% {
height: 0px;
}
100% {
height: var(--corvu-disclosure-content-height);
}
}
@keyframes collapse {
0% {
height: var(--corvu-disclosure-content-height);
}
100% {
height: 0px;
}
}
.content_wrapper {
padding-left: 1rem;
padding-right: 1rem;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
}
Features
- Option to hide the content instead of unmounting for better SEO
- CSS variables to animate the height/width of every item content
- Full keybard navigation
Usage
import Accordion from 'corvu/accordion'
// Or
// import { Root, Trigger, ... } from 'corvu/accordion'
Anatomy
<Accordion.Root>
<Accordion.Item>
<Accordion.Trigger />
<Accordion.Content />
</Accordion.Item>
</Accordion.Root>
The accordion item uses the Disclosure component under the hood. It forwards the same props in the Root children callback and corvu/accordion
also exports the useContext
function as useDisclosureContext
.
Animation
Corvu sets the --corvu-disclosure-content-height
and --corvu-disclosure-content-width
css properties on every accordion item content that make it possible to animate the height/width.
[data-corvu-accordion-content][data-collapsed] {
animation: collapse 200ms linear;
}
[data-corvu-accordion-content][data-expanded] {
animation: expand 200ms linear;
}
@keyframes collapse {
0% {
height: var(--corvu-disclosure-content-height);
}
100% {
height: 0px;
}
}
@keyframes expand {
0% {
height: 0px;
}
100% {
height: var(--corvu-disclosure-content-height);
}
}
Accessibility
Adheres to the Accordion WAI-ARIA design pattern.
Ensuring items are accessible
Based on the Accordion WAI-ARIA design pattern, every accordion item trigger should include a meaninful title text and the trigger should be wrapped in a heading element like this:
<Accordion.Item>
<h2>
<Accordion.Trigger>Title</Accordion.Trigger>
</h2>
<Accordion.Content />
</Accordion.Item>
Keyboard navigation
Key | Behavior |
---|---|
Space | When the trigger of an item is focused, toggles the item content. |
Enter | When the trigger of an item is focused, toggles the item content. |
Tab | Moves focus to the next focusable element. |
Shift + Tab | Moves focus to the previous focusable element. |
ArrowDown | When the trigger of an item is focused, moves to the next trigger |
ArrowDown | When the trigger of an item is focused, moves to the previous trigger |
Home | When the trigger of an item is focused, moves to the first trigger |
End | When the trigger of an item is focused, moves to the first trigger |
API reference
Accordion.Root
Component
Context wrapper for the accordion. Is required for every accordion you create.
Props
multiple
boolean
Whether multiple accordion items can be expanded at the same time. *Default = false
*
value
string | [string] | null
The value of the accordion.
onValueChange
(value: string | [string] | null) => void
Callback fired when the value changes.
initialValue
string | [string] | null
The value of the accordion initially. *Default = null
*
collapsible
boolean
Whether the accordion can be fully collapsed or not. *Default = true
*
disabled
boolean
Whether the accordion is disabled or not. *Default = false
*
orientation
'vertical' | 'horizontal'
The orientation of the accordion. *Default = vertical
*
loop
boolean
Whether the accordion should loop when navigating with the keyboard. *Default = true
*
collapseBehavior
'remove' | 'hide'
Whether the accordion content should be removed or hidden when collapsed. Useful if you want to always render the content for SEO reasons. *Default = remove
*
contextId
string
The id
of the accordion context. Useful if you have nested accordions and want to create components that belong to a accordion higher up in the tree.
children
JSX.Element | (props: AccordionRootChildrenProps) => JSX.Element
Accordion.Item
Component
Context wrapper for the accordion item. Is required for every accordion item you create.
Props
value
string
Value of the accordion item. If none is provided, createUniqueId
will be used to create one.
disabled
boolean
Whether the accordion item is disabled. Used to override the default provided by <Accordion.Root>
.
triggerId
string
The id
attribute of the accordion item trigger element. *Default = A unique id.*
collapseBehavior
'remove' | 'hide'
Whether the disclosure content should be removed or hidden when collapsed. Useful if you want to always render the content for SEO reasons. *Default = remove
*
disclosureId
string
The id
attribute of the disclosure content element. *Default = A unique id.*
contextId
string
The id
of the disclosure context. Useful if you have nested disclosures and want to create components that belong to a disclosure higher up in the tree.
children
JSX.Element | (props: ItemChildrenProps) => JSX.Element
as
ValidComponent
Default: Fragment
Component to render the polymorphic component as. *Default = div
*
asChild
boolean
Whether to render the polymorphic component as the first <As />
component found in its children. *Default = false
*
Accordion.Trigger
Component
Button that changes the open state of the accordion item when clicked.
Props
as
ValidComponent
Default: button
Component to render the polymorphic component as. *Default = div
*
asChild
boolean
Whether to render the polymorphic component as the first <As />
component found in its children. *Default = false
*
contextId
string
The id
of the accordion context to use.
Data
Data attributes present on primitives/accordion.Trigger components.
data-corvu-accordion-trigger
Present on every accordion trigger element.
data-expanded
Present when the accordion is expanded.
data-collapsed
Present when the accordion is collapsed.
data-disabled
Present when the accordion trigger is disabled.
CSS props
CSS properties attributes present on primitives/accordion.Trigger components.
Accordion.Content
Component
Content of an accordion item. Can be animated.
Props
forceMount
boolean
Whether the disclosure content should be forced to render. Useful when using third-party animation libraries.
contextId
string
The id
of the disclosure context to use.
as
ValidComponent
Default: div
Component to render the polymorphic component as. *Default = div
*
asChild
boolean
Whether to render the polymorphic component as the first <As />
component found in its children. *Default = false
*
Data
Data attributes present on primitives/accordion.Content components.
data-corvu-accordion-content
Present on every accordion item content element.
data-expanded
Present when the accordion item is expanded.
data-collapsed
Present when the accordion item is collapsed.
CSS props
CSS properties attributes present on primitives/accordion.Content components.
--corvu-disclosure-content-width
The width of the accordion item content. Useful if you want to animate its width.
--corvu-disclosure-content-height
The height of the accordion item content. Useful if you want to animate its height.
Accordion.useContext
Context
Context which exposes various properties to interact with the accordion. Optionally provide a contextId to access a keyed context.
Returns
multiple
Accessor<boolean>
Whether multiple accordion items can be expanded at the same time.
value
Accessor<string | [string] | null>
The value of the accordion.
setValue
Setter<string | [string] | null>
Callback fired when the value changes.
collapsible
Accessor<boolean>
Whether the accordion can be fully collapsed or not.
disabled
Accessor<boolean>
Whether the accordion is disabled or not.
orientation
Accessor<'horizontal' | 'vertical'>
The orientation of the accordion.
loop
Accessor<boolean>
Whether the accordion should loop when navigating with the keyboard.
collapseBehavior
Accessor<'remove' | 'hide'>
Whether the accordion item content should be removed or hidden when collapsed.
Accordion.useItemContext
Context
Context which exposes various properties to interact with the accordion. Optionally provide a contextId to access a keyed context.
Returns
value
Accessor<string>
Value of the accordion item.
disabled
Accessor<boolean>
Whether the accordion item is disabled.
triggerId
Accessor<string | undefined>
The id
attribute of the accordion item trigger element.
Accordion.RootChildrenProps
Type
Props which are passed to the Root component children function.
Props
multiple
boolean
Whether multiple accordion items can be expanded at the same time.
value
string | [string] | null
The value of the accordion.
setValue
Setter<string | [string] | null>
Callback fired when the value changes.
collapsible
boolean
Whether the accordion can be fully collapsed or not.
disabled
boolean
Whether the accordion is disabled or not.
orientation
'horizontal' | 'vertical'
The orientation of the accordion.
loop
boolean
Whether the accordion should loop when navigating with the keyboard.
collapseBehavior
'remove' | 'hide'
Whether the accordion content should be removed or hidden when collapsed.
Accordion.ItemChildrenProps
Type
Props which are passed to the Item component children function.
Props
value
string
Value of the accordion item.
disabled
boolean
Whether the accordion item is disabled.
triggerId
string | undefined
The id
attribute of the accordion item trigger element.
corvu@0.2.3
Developed and designed by Jasmin