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
/** @type {import('tailwindcss').Config} */
export default {
content: ['./src/**/*.{ts,tsx}'],
theme: {
extend: {
colors: {
corvu: {
bg: '#f3f1fe',
100: '#e6e2fd',
200: '#d4cbfb',
300: '#bcacf6',
400: '#a888f1',
},
},
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: [require('@corvu/tailwind')],
}
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.
<Root />
Component
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 |
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. |
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. |
<Item />
Component
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. |
<Trigger />
Component
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 />
Component
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. |
useContext
Context
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. |
collapseBehavior | Accessor<'remove' | 'hide'> Whether the accordion item content should be removed or hidden when collapsed. |
useItemContext
Context
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. |
useDisclosureContext
Context
Inherited from <Disclosure.useContext />
.
RootChildrenProps
Type
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. |
collapseBehavior | 'remove' | 'hide' Whether the accordion content should be removed or hidden when collapsed. |
ItemChildrenProps
Type
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