Accordion
The accordion
component provides a way to display a list of items that can be
expanded or collapsed.
Features
Multiple items
The accordion
component supports multiple expanded items, if configured to do so.
Keyboard navigation
- Space or Enter on a collapsed item expands it.
- Escape on an expanded item collapses it.
- Arrow Up or Arrow Down navigates between items.
- Home or End navigates to the first or last item.
Example
Lion
Elephant
Elephants are herbivorous and consume a variety of plant materials,
including grass, leaves, and fruits.
Giraffe
Tiger
Bear
Sources
+page.svelte
<script lang="ts">
import Accordion from './Accordion.svelte'
import AccordionItem from './AccordionItem.svelte'
</script>
<Accordion>
<AccordionItem heading="Lion" icon="🦁">
Lions are carnivorous and primarily feed on large ungulates, such as zebras
and wildebeests.
</AccordionItem>
<AccordionItem heading="Elephant" icon="🐘" open>
Elephants are herbivorous and consume a variety of plant materials,
including grass, leaves, and fruits.
</AccordionItem>
<AccordionItem heading="Giraffe" icon="🦒" disabled>
Giraffes are herbivorous and consume a variety of leaves and buds of acacia,
mimosa, and wild apricot trees.
</AccordionItem>
<AccordionItem heading="Tiger" icon="🐯">
Tigers are carnivorous and mainly prey on ungulates, such as deer and wild
boar.
</AccordionItem>
<AccordionItem heading="Bear" icon="🐻" disabled>
Bears are omnivorous and feed on a variety of plant and animal foods and
insects.
</AccordionItem>
</Accordion>
Accordion.svelte
<script lang="ts">
import { createAccordion } from 'louisette'
import { setContext } from 'svelte'
const { accordionAttrs, ...accordionContext } = createAccordion()
setContext('accordion', accordionContext)
</script>
<div {...$accordionAttrs}>
<slot />
</div>
AccordionItem.svelte
<script lang="ts">
import { createKey, type Accordion } from 'louisette'
import { getContext } from 'svelte'
export let icon: string = ''
export let heading: string
export let disabled: boolean = false
export let open: boolean = false
// Generate a random key for this accordion item
const key = createKey()
const { triggerAttrs, contentAttrs, expanded, expand, disable } =
getContext<Accordion>('accordion')
if (open) {
expand(key)
}
if (disabled) {
disable(key)
}
</script>
<div
class="border border-neutral-200 bg-white text-neutral-900 shadow-sm first:rounded-t-lg last:rounded-b-lg dark:border-neutral-600 dark:bg-neutral-800 dark:text-neutral-100 [&:not(:first-child)]:border-t-0"
>
<div
{...$triggerAttrs(key)}
class="flex cursor-pointer select-none items-center rounded-sm px-5 py-4 font-semibold leading-5 transition-colors duration-200 ease-in-out hover:bg-neutral-100 focus-visible:bg-neutral-100 dark:hover:bg-neutral-700 dark:focus-visible:bg-neutral-700"
class:is-disabled={disabled}
>
{#if icon}
<span class="mr-3" aria-hidden="true">{icon}</span>
{/if}
{heading}
<span class="ml-auto" class:rotate-180={$expanded.includes(key)}>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="h-4 w-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M19.5 8.25l-7.5 7.5-7.5-7.5"
/>
</svg>
</span>
</div>
<div
{...$contentAttrs(key)}
class="px-5 py-4 text-sm leading-5 transition-colors duration-200 ease-in-out"
class:hidden={!$expanded.includes(key)}
>
<slot />
</div>
</div>
<style lang="postcss">
.is-disabled {
@apply pointer-events-none opacity-50;
}
</style>