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 collapseBehavior="hide">
<Accordion.Item>
<h2>
<Accordion.Trigger class="w-full border-b border-corvu-300 bg-corvu-100 px-4 py-3 text-left font-medium transition-all duration-100 hover:bg-corvu-200 focus-visible:bg-corvu-200 focus-visible:outline-none">
What is corvu?
</Accordion.Trigger>
</h2>
<Accordion.Content class="overflow-hidden border-b border-corvu-300 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>
<h2>
<Accordion.Trigger class="w-full border-b border-corvu-300 bg-corvu-100 px-4 py-3 text-left font-medium transition-all duration-100 hover:bg-corvu-200 focus-visible:bg-corvu-200 focus-visible:outline-none">
Is it accessible?
</Accordion.Trigger>
</h2>
<Accordion.Content class="overflow-hidden border-b border-corvu-300 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>
<h2>
<Accordion.Trigger class="w-full border-b border-corvu-300 bg-corvu-100 px-4 py-3 text-left font-medium transition-all duration-100 hover:bg-corvu-200 focus-visible:bg-corvu-200 focus-visible:outline-none">
Can I customize it?
</Accordion.Trigger>
</h2>
<Accordion.Content class="overflow-hidden border-b border-corvu-300 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>
</div>
)
}
export default AccordionExample
import corvuPlugin from '@corvu/tailwind'
/** @type {import('tailwindcss').Config} */
export default {
content: ['./src/**/*.{ts,tsx}'],
theme: {
extend: {
colors: {
corvu: {
bg: '#f3f1fe',
100: '#e6e2fd',
200: '#d4cbfb',
300: '#bcacf6',
400: '#a888f1',
text: '#180f24',
},
},
animation: {
expand: 'expand 250ms cubic-bezier(0.32,0.72,0,0.75)',
collapse: 'collapse 250ms cubic-bezier(0.32,0.72,0,0.75)',
},
keyframes: {
expand: {
'0%': {
height: '0px',
},
'100%': {
height: 'var(--corvu-disclosure-content-height)',
},
},
collapse: {
'0%': {
height: 'var(--corvu-disclosure-content-height)',
},
'100%': {
height: '0px',
},
},
},
},
},
plugins: [corvuPlugin],
}
import Accordion from '@corvu/accordion'
import type { VoidComponent } from 'solid-js'
const AccordionExample: VoidComponent = () => {
return (
<div class="wrapper">
<Accordion collapseBehavior="hide">
<Accordion.Item>
<h2>
<Accordion.Trigger>What is corvu?</Accordion.Trigger>
</h2>
<Accordion.Content>
<div class="content_wrapper">
A collection of unstyled, customizable UI primitives for SolidJS.
</div>
</Accordion.Content>
</Accordion.Item>
<Accordion.Item>
<h2>
<Accordion.Trigger>Is it accessible?</Accordion.Trigger>
</h2>
<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>
<h2>
<Accordion.Trigger>Can I customize it?</Accordion.Trigger>
</h2>
<Accordion.Content>
<div class="content_wrapper">
Yes, check out the API reference at the bottom for all options.
</div>
</Accordion.Content>
</Accordion.Item>
</Accordion>
</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: hsl(253, 80%, 82%);
background-color: hsl(249, 87%, 94%);
padding-left: 1rem;
padding-right: 1rem;
padding-top: 0.75rem;
padding-bottom: 0.75rem;
text-align: left;
font-weight: 500;
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: hsl(251, 86%, 89%);
}
[data-corvu-accordion-trigger]:focus-visible {
outline: 2px solid transparent;
outline-offset: 2px;
background-color: hsl(251, 86%, 89%);
}
[data-corvu-accordion-content] {
border-bottom-width: 1px;
overflow: hidden;
border-color: hsl(253, 80%, 82%);
background-color: hsl(249, 87%, 94%);
}
[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 Section titled Features
- Option to hide the content when collapsed instead of unmounting it for better SEO
- CSS variables to animate the height/width of every item content
- Full keyboard navigation
Installation Section titled Installation
npm install @corvu/accordion
The accordion is also included in the main corvu
package under corvu/accordion
.
Usage Section titled Usage
import Accordion from '@corvu/accordion' // 'corvu/accordion'
// or
// import { Root, Trigger, ... } from '@corvu/accordion'
Anatomy Section titled Anatomy
<Accordion>
<Accordion.Item>
<Accordion.Trigger />
<Accordion.Content />
</Accordion.Item>
</Accordion>
The accordion item uses the Disclosure component under the hood. It forwards the same props in the Item children callback and the disclosure context is re-exported as Accordion.useDisclosureContext
.
Animation Section titled 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 Section titled Accessibility
Adheres to the Accordion WAI-ARIA design pattern.
Ensuring items are accessible Section titled Ensuring items are accessible
Based on the Accordion WAI-ARIA design pattern, every accordion item trigger should include a meaningful title text and should be wrapped in a heading element like this:
<Accordion.Item>
<h3>
<Accordion.Trigger>What is corvu?</Accordion.Trigger>
</h3>
<Accordion.Content />
</Accordion.Item>
If you don’t want to use a heading element for some reason, you can instead use the aria-level
attribute to define the hierarchical level:
<Accordion.Item>
<span aria-level="3">
<Accordion.Trigger>What is corvu?</Accordion.Trigger>
</span>
<Accordion.Content />
</Accordion.Item>
Keyboard navigation Section titled 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 and orientation is 'vertical' (default), moves to the next trigger. |
ArrowUp | When the trigger of an item is focused and orientation is 'vertical' (default), moves to the previous trigger. |
ArrowRight | When the trigger of an item is focused and orientation is 'horizontal', moves to the next trigger. |
ArrowLeft | When the trigger of an item is focused and orientation is 'horizontal', 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 Section titled API reference
The disclosure context is re-exported as Accordion.useDisclosureContext
and the item children callback also accepts all props of the disclosure root children callback, which are documented in the Disclosure API reference.
Context wrapper for the accordion. Is required for every accordion you create.
Props
Property | Default | Type/Description |
---|---|---|
multiple | false | boolean Whether multiple accordion items can be expanded at the same time. |
value | - | string | string[] | null The value of the accordion. |
onValueChange | - | (value: string | string[] | null) => void Callback fired when the value changes. |
initialValue | null | string | string[] | null The value of the accordion initially. |
collapsible | true | boolean Whether the accordion can be fully collapsed. |
disabled | false | boolean Whether the accordion is disabled. |
orientation | vertical | 'vertical' | 'horizontal' The orientation of the accordion. |
loop | true | boolean Whether the accordion should loop when navigating with the keyboard. |
textDirection | ltr | 'ltr' | 'rtl' The text direction of the accordion. |
collapseBehavior | remove | '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. |
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. |
Context wrapper for the accordion item. Is required for every accordion item you create.
Props
Inherits <Disclosure.Root />
Props.
Property | Default | Type/Description |
---|---|---|
value | createUniqueId() | string Value of the accordion item. |
disabled | - | boolean Whether the accordion item is disabled. Used to override the default provided by . |
triggerId | createUniqueId() | string The id attribute of the accordion item trigger element. |
as | Fragment | ValidComponent Component to render the dynamic component as. |
Data attributes
Data attributes present on <Item />
components.
Property | Description |
---|---|
data-corvu-accordion-item | Present if the item isn't rendered as a Fragment. |
Button that changes the open state of the accordion item when clicked.
Props
Inherits <Disclosure.Trigger />
Props.
Data attributes
Data attributes present on <Trigger />
components.
Property | Description |
---|---|
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. |
Content of an accordion item. Can be animated.
Props
Inherits <Disclosure.Content />
Props.
Data attributes
Data attributes present on <Content />
components.
Property | Description |
---|---|
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 properties
CSS properties present on <Content />
components.
Property | Description |
---|---|
--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. |
Context which exposes various properties to interact with the accordion. Optionally provide a contextId to access a keyed context.
Returns
Property | Type/Description |
---|---|
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. |
disabled | Accessor<boolean> Whether the accordion is disabled. |
orientation | Accessor<'horizontal' | 'vertical'> The orientation of the accordion. |
loop | Accessor<boolean> Whether the accordion should loop when navigating with the keyboard. |
textDirection | Accessor<'ltr' | 'rtl'> The text direction of the accordion. |
collapseBehavior | Accessor<'remove' | 'hide'> Whether the accordion item content should be removed or hidden when collapsed. |
Context which exposes various properties to interact with the accordion. Optionally provide a contextId to access a keyed context.
Returns
Property | Type/Description |
---|---|
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. |
Inherited from <Disclosure.useContext />
.
Props that are passed to the Root component children callback.
Props
Property | Type/Description |
---|---|
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. |
disabled | boolean Whether the accordion is disabled. |
orientation | 'horizontal' | 'vertical' The orientation of the accordion. |
loop | boolean Whether the accordion should loop when navigating with the keyboard. |
textDirection | 'ltr' | 'rtl' The text direction of the accordion. |
collapseBehavior | 'remove' | 'hide' Whether the accordion content should be removed or hidden when collapsed. |
Props that are passed to the Item component children callback.
Props
Inherits <Disclosure.RootChildrenProps />
Props.
Property | Type/Description |
---|---|
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. |
Developed and designed by Jasmin