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. (Default behavior) |
Shift + Tab | Moves focus to the previous focusable element. (Default behavior) |
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
children
JSX.Element | (props: AccordionRootChildrenProps) => JSX.Element
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
*
collapsible
boolean
Whether the accordion can be fully collapsed or not. *Default = true
*
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.
disabled
boolean
Whether the accordion is disabled or not. *Default = false
*
initialValue
string | [string] | 'null'
The value of the accordion initially. *Default = null
*
loop
boolean
Whether the accordion should loop when navigating with the keyboard. *Default = true
*
multiple
boolean
Whether multiple accordion items can be expanded at the same time. *Default = false
*
onValueChange
(value: string | [string] | 'null') => void
Callback fired when the value changes.
orientation
'vertical' | 'horizontal'
The orientation of the accordion. *Default = vertical
*
value
string | [string] | 'null'
The value of the accordion.
Accordion.Item
Component
Context wrapper for the accordion item. Is required for every accordion item you create.
Props
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
*
children
JSX.Element | (props: ItemChildrenProps) => JSX.Element
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
*
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.
disabled
boolean
Whether the accordion item is disabled. Used to override the default provided by <Accordion.Root>
.
disclosureId
string
The id
attribute of the disclosure content element. *Default = A unique id.*
triggerId
string
The id
attribute of the accordion item trigger element. *Default = A unique id.*
value
string
Value of the accordion item. If none is provided, createUniqueId
will be used to create one.
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.
Accordion.Content
Component
Content of an accordion item. Can be animated.
Props
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
*
contextId
string
The id
of the disclosure context to use.
forceMount
boolean
Whether the disclosure content should be forced to render. Useful when using third-party animation libraries.
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.
Accordion.useContext
Context
Context which exposes various properties to interact with the accordion. Optionally provide a contextId to access a keyed context.
Returns
collapseBehavior
Accessor<'remove' | 'hide'>
Whether the accordion item content should be removed or hidden when collapsed.
collapsible
Accessor<boolean>
Whether the accordion can be fully collapsed or not.
disabled
Accessor<boolean>
Whether the accordion is disabled or not.
loop
Accessor<boolean>
Whether the accordion should loop when navigating with the keyboard.
multiple
Accessor<boolean>
Whether multiple accordion items can be expanded at the same time.
orientation
Accessor<'horizontal' | 'vertical'>
The orientation of the accordion.
setValue
Setter<string | [string] | 'null'>
Callback fired when the value changes.
value
Accessor<string | [string] | 'null'>
The value of the accordion.
Accordion.useItemContext
Context
Context which exposes various properties to interact with the accordion. Optionally provide a contextId to access a keyed context.
Returns
disabled
Accessor<boolean>
Whether the accordion item is disabled.
triggerId
Accessor<string | undefined>
The id
attribute of the accordion item trigger element.
value
Accessor<string>
Value of the accordion item.
Accordion.RootChildrenProps
Type
Props which are passed to the Root component children function.
Props
collapseBehavior
'remove' | 'hide'
Whether the accordion content should be removed or hidden when collapsed.
collapsible
boolean
Whether the accordion can be fully collapsed or not.
disabled
boolean
Whether the accordion is disabled or not.
loop
boolean
Whether the accordion should loop when navigating with the keyboard.
multiple
boolean
Whether multiple accordion items can be expanded at the same time.
orientation
'horizontal' | 'vertical'
The orientation of the accordion.
setValue
Setter<string | [string] | 'null'>
Callback fired when the value changes.
value
string | [string] | 'null'
The value of the accordion.
Accordion.ItemChildrenProps
Type
Props which are passed to the Item component children function.
Props
disabled
boolean
Whether the accordion item is disabled.
triggerId
string | undefined
The id
attribute of the accordion item trigger element.
value
string
Value of the accordion item.
corvu@0.2.3
Developed and designed by Jasmin