Accordion
Accordionは、クリックするとコンテンツが展開・折りたためる見出しのリストです。
必要な情報をコンパクトに整理し、ユーザーが見たい内容だけを表示できます。
<script lang="ts">
import Accordion from '$lib/components/ui/atoms/Accordion.svelte';
</script>
<div class="flex flex-col size-full">
<Accordion title="項目1">ここにコンテンツ内容が入ります</Accordion>
<Accordion title="項目2">ここにコンテンツ内容が入ります</Accordion>
<Accordion title="項目3">ここにコンテンツ内容が入ります</Accordion>
</div>
プロパティ
Accordionは、以下のプロパティをサポートしています。
| 名前 | 型 | デフォルト値 | 説明 |
|---|---|---|---|
title |
string |
見出しの文言を設定できます。 |
インストールの手順
以下のコンポーネントのコードを、使いたいプロジェクトにコピー&ペーストします。
パスは実際のプロジェクトの構成にあわせて更新します。
atoms/Accordion.svelte
<!--
@component
## 概要
- detailsタグ・summaryタグのように、クリックなどのユーザー操作で開閉に対応する汎用的なアコーディオンコンポーネントです
## 機能
- detailsタグ・summaryタグと同様に、クリックやフォーカスなどのインタラクションに対応します
## Props
- title: 見出しの文言を設定できます
## Usage
```svelte
<Accordion title='項目'>ここにコンテンツ内容が入ります</Accordion>
```
-->
<script module lang="ts">
import type { Snippet } from 'svelte';
import type { ClassValue } from 'svelte/elements';
import { cva, type VariantProps } from 'class-variance-authority';
export let accordionVariants = cva('w-full border-b-1 border-base-stroke-default');
export let accordionTitleVariants = cva('relative py-4 pr-7.5 pl-2 text-base text-base-foreground-default list-none outline-primary transition cursor-pointer hover:bg-base-container-accent/90 focus-visible:outline-[0.125rem] focus-visible:outline-offset-[0.125rem] focus-visible:outline-primary focus-visible:!rounded-sm');
export let accordionDescriptionVariants = cva('px-2 pb-4 text-base-foreground-default text-sm');
export type AccordionVariants = VariantProps<typeof accordionVariants>;
export interface AccordionProps extends AccordionVariants {
/** タイトル */
title: string;
/** クラス */
class?: ClassValue;
children: Snippet<[]>;
}
</script>
<script lang="ts">
import { ChevronDown } from '@lucide/svelte';
let { title, class: className, children } = $props();
const animTiming = {
duration: 250,
easing: 'ease-out',
};
let detailsElement;
let summaryElement;
let descriptionContainer;
let isOpen = $state(false);
let accordionVariantClass = $derived(accordionVariants({ class: className }));
function closeAnimKeyframes() {
return [
{
height: descriptionContainer.offsetHeight + 'px', // height: "auto"だとうまく計算されないため要素の高さを指定する
opacity: 1,
},
{
height: 0,
opacity: 0,
},
];
}
function openAnimKeyframes() {
return [
{
height: 0,
opacity: 0,
},
{
height: descriptionContainer.offsetHeight + 'px',
opacity: 1,
},
];
}
function onToggleSummaryAnim(e) {
e.preventDefault();
if (detailsElement.open) {
const close_anim = descriptionContainer.animate(closeAnimKeyframes(), animTiming);
isOpen = false;
close_anim.onfinish = () => {
// アニメーションの完了後にopen属性を取り除く
detailsElement.removeAttribute('open');
};
}
else {
detailsElement.setAttribute('open', 'true');
isOpen = true;
descriptionContainer.animate(openAnimKeyframes(), animTiming);
}
}
</script>
<details class={accordionVariantClass} bind:this={detailsElement}>
<summary class={accordionTitleVariants()} bind:this={summaryElement} onclick={onToggleSummaryAnim}>
{title}
<ChevronDown class={['absolute inset-y-0 right-2 transition duration-300 my-auto', { 'rotate-180': isOpen }]} size="1rem" />
</summary>
<div class="overflow-hidden" bind:this={descriptionContainer}>
<div class={accordionDescriptionVariants()}>
{@render children()}
</div>
</div>
</details>
使い方
<script lang="ts">
import Accordion from '$lib/components/ui/atoms/Accordion.svelte';
</script>
<div class="flex flex-col size-full">
<Accordion title="項目1">ここにコンテンツ内容が入ります</Accordion>
<Accordion title="項目2">ここにコンテンツ内容が入ります</Accordion>
<Accordion title="項目3">ここにコンテンツ内容が入ります</Accordion>
</div>
サンプル
Default
特に操作が行われていない、デフォルトの状態です。
<script lang="ts">
import Accordion from '$lib/components/ui/atoms/Accordion.svelte';
</script>
<div class="flex flex-col size-full">
<Accordion title="項目1">ここにコンテンツ内容が入ります</Accordion>
<Accordion title="項目2">ここにコンテンツ内容が入ります</Accordion>
<Accordion title="項目3">ここにコンテンツ内容が入ります</Accordion>
</div>