テーマカラーの定義を更新しました

最新のCSSを確認

Accordion

Accordionは、クリックするとコンテンツが展開・折りたためる見出しのリストです。
必要な情報をコンパクトに整理し、ユーザーが見たい内容だけを表示できます。

プロパティ

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';

  const ANIMATION_DURATION = 250;
  const ANIMATION_EASING = 'ease-out';

  export const accordionVariants = cva('w-full border-b-1 border-border');

  export const accordionTitleVariants = cva('relative py-4 pr-7.5 pl-2 text-base text-foreground list-none outline-offset-2 outline-ring transition cursor-pointer hover:bg-accent/90 focus-visible:outline-2 focus-visible:!rounded-sm');

  export const accordionDescriptionVariants = cva('px-2 pb-4 text-foreground 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: ANIMATION_DURATION,
    easing: ANIMATION_EASING,
  };

  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 handleToggleSummaryAnim(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} data-rabee-ui="accordion">
  <summary class={accordionTitleVariants()} bind:this={summaryElement} onclick={handleToggleSummaryAnim}>
    {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>

      

使い方


サンプル

Default

特に操作が行われていない、デフォルトの状態です。