Accordion
A UI component for creating accordion elements.
It is built with <div> / <button> elements rather than <details> / <summary>, and uses JavaScript to control the open/close animation.
The panel uses hidden="until-found", so its content can be discovered by the browser’s in-page search even when the accordion is closed, and the panel will automatically expand when a match is found.
Lorem ipsum dolor sit amet. Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut. Aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint.
Lorem ipsum dolor sit amet. Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut. Aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint.
<Accordion.Root> <Accordion.Item> <Accordion.Heading> <Accordion.Button p="20">Accordion Example</Accordion.Button> </Accordion.Heading> <Accordion.Panel p="20" pt="5"> <DummyText length="l" /> </Accordion.Panel> </Accordion.Item> <Accordion.Item bd-t> <Accordion.Heading> <Accordion.Button p="20">Accordion Example 2</Accordion.Button> </Accordion.Heading> <Accordion.Panel p="20" pt="5"> <DummyText length="l" /> </Accordion.Panel> </Accordion.Item></Accordion.Root>Usage
Provided as Accordion from the @lism-css/ui package.
Import
import { Accordion } from '@lism-css/ui/react'; The following components are available:
<Accordion.Root>: The root element wrapping multiple accordion items (based onStack)<Accordion.Item>: An individual accordion element<Accordion.Heading>: Wrapper for the heading area (defaults to<div role="heading">)<Accordion.Button>: The toggle button (automatically includes<Accordion.Icon>at the end)<Accordion.Icon>: The open/close state indicator icon (rendered via CSS pseudo-elements)<Accordion.Panel>: The content panel that opens and closes (useshidden="until-found")
Props
| Prop | Description |
|---|---|
<Accordion.Root> allowMultiple | Allows multiple accordions to be expanded simultaneously. By default, only one can be open at a time. |
<Accordion.Item> isOpen | Expands the item by default (adds data-opened). Use together with isOpen on <Accordion.Button> / <Accordion.Panel>. |
<Accordion.Heading> as | Specifies the HTML tag for the heading. Defaults to div (with role="heading" added automatically). If h2–h6 is specified, role is not added. |
<Accordion.Button> isOpen | Sets aria-expanded to match the initial expanded state. |
<Accordion.Panel> flow | Flow layout setting passed to the content area (__content) inside the panel. |
<Accordion.Panel> isOpen | Shows the panel by default (removes hidden). |
Structure
<Accordion.Root> <Accordion.Item> <Accordion.Heading> <Accordion.Button>Accordion Label</Accordion.Button> </Accordion.Heading> <Accordion.Panel p="20" pt="5"> ...Contents... </Accordion.Panel> </Accordion.Item></Accordion.Root><Accordion.Button> automatically includes <Accordion.Icon> at the end.
The icon is rendered using CSS pseudo-elements (::before / ::after), so no SVG specification is needed.
Source Code
The source code is available on GitHub.
Examples
Changing the heading tag
<Accordion.Heading> outputs a <div role="heading"> by default, but you can specify a heading tag like h3 via the as prop to render it as an actual heading element.
Lorem ipsum dolor sit amet. Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut. Aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint.
Lorem ipsum dolor sit amet. Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut. Aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint.
<Accordion.Root bd> <Accordion.Item> <Accordion.Heading as="h3"> <Accordion.Button p="20">Accordion Label</Accordion.Button> </Accordion.Heading> <Accordion.Panel p="20" pt="5"> <DummyText length="l" /> </Accordion.Panel> </Accordion.Item> <Accordion.Item bd-t> <Accordion.Heading as="h3"> <Accordion.Button p="20">Accordion Label</Accordion.Button> </Accordion.Heading> <Accordion.Panel p="20" pt="5"> <DummyText length="l" /> </Accordion.Panel> </Accordion.Item></Accordion.Root>Changing the animation duration
The speed of the open/close animation is controlled by the --duration variable, which defaults to 0.25s.
You can change it by setting the CSS variable on <Accordion.Root> (for all items) or on an individual <Accordion.Item>.
Lorem ipsum dolor sit amet. Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut. Aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint.
Lorem ipsum dolor sit amet. Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut. Aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint.
<Accordion.Root style={{ '--duration': '.15s' }}> <Accordion.Item> <Accordion.Heading> <Accordion.Button p="20">Accordion Example 1</Accordion.Button> </Accordion.Heading> <Accordion.Panel p="20" pt="5"> ... </Accordion.Panel> </Accordion.Item> ...</Accordion.Root>Opening the first item by default
To have an item expanded from the start, specify isOpen on each of <Accordion.Item>, <Accordion.Button>, and <Accordion.Panel>.
Because isOpen plays a different role on each component, specify it on all three.
On <Accordion.Item> it adds data-opened to set the panel height and icon to the open state, on <Accordion.Button> it controls aria-expanded, and on <Accordion.Panel> it toggles hidden.
Lorem ipsum dolor sit amet. Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut. Aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint.
Lorem ipsum dolor sit amet. Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut. Aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint.
<Accordion.Root bd> <Accordion.Item isOpen> <Accordion.Heading> <Accordion.Button p="20" isOpen>Accordion Label 1</Accordion.Button> </Accordion.Heading> <Accordion.Panel p="20" pt="5" isOpen> ... </Accordion.Panel> </Accordion.Item> <Accordion.Item bd-t> <Accordion.Heading> <Accordion.Button p="20">Accordion Label 2</Accordion.Button> </Accordion.Heading> <Accordion.Panel p="20" pt="5"> ... </Accordion.Panel> </Accordion.Item></Accordion.Root>Allowing multiple panels to be open
By default, only one accordion within the same <Accordion.Root> can be expanded at a time.
Specifying allowMultiple allows multiple panels to be open simultaneously.
Lorem ipsum dolor sit amet. Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut. Aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint.
Lorem ipsum dolor sit amet. Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut. Aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint. Occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis undeomnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam.
Lorem ipsum dolor sit amet. Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut. Aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint.
<Accordion.Root allowMultiple bd> <Accordion.Item> <Accordion.Heading> <Accordion.Button p="20">Accordion Label 1</Accordion.Button> </Accordion.Heading> <Accordion.Panel p="20" pt="5"> ... </Accordion.Panel> </Accordion.Item> <Accordion.Item bd-t> <Accordion.Heading> <Accordion.Button p="20">Accordion Label 2</Accordion.Button> </Accordion.Heading> <Accordion.Panel p="20" pt="5"> ... </Accordion.Panel> </Accordion.Item> ...</Accordion.Root>