アコーディオンメニューの実装:React Spring

アコーディオンメニューの実装:React Spring

ども!React Springの第三弾になります。構築済みUIなどで見られる『アコーディオン』を実装しました。実装パターンが複数ありますが、CSSプロパティに寄せているので実装コストは少ないかと思います。TailwindとReact Iconsを使用していればそのまま利用することができる構築済みUI(笑)になっています。

無駄話というか導入

ども!体調不良から順調に復帰をしている龍ちゃんです。唐突なインフルエンザで、出張は台無しになり悲しんだネタすらブログになっています。2日ほど仕事中にダウンして、そこからも絶妙に体調不良が続いていたので、仕事がずれ込んでますね。なぁ~んでもブログネタになるので乾杯って感じですね。

今回もReact Springのネタになります。今回取り扱うシナリオとしては、「アコーディオン」になります。以下の動画がサンプルになります。実際のサイトアクセスはこちらです。

実装

環境セットアップとサンプルコードをさっくりと紹介していきます。

環境とセットアップ

それでは、セットアップと使用方法についてまとめていきます。インストール自体は、安心コマンド一発になります。

yarn add @react-spring/web

あとは、要素の部分を以下に変更することで動作します。

import { animated } from '@react-spring/web'

export default function MyComponent() {
  return (
    <animated.div
      style={
				<-- アニメーションの定義をここで書くとええ感じの動作する -->
			}
    />
  )
}

これだけでアニメーションを定義することができるので、非常に楽で便利です。環境としては以下のライブラリを使用しています。コピペをする場合は、事前にセットアップとインストールをお願いします。

アコーディオン的ににゅっと伸びるデザイン

アコーディオン的な実装をする方法としては、以下の3パターンあるそうです。

  • maxHeightを使用して要素よりも大きい値を設定する
  • DOMの高さを計算してReact Springのアニメーション計算を行う
  • CSS gridデザインのgrid-template-rowsを使用してアニメーション適応をする

今回は、『gridデザイン』を使用したデザインパターンで実装しています。サンプルコードは以下になります。

import { useState } from 'react';

import { animated, useChain, useSpring, useSpringRef } from '@react-spring/web';
import { FaCaretDown, FaCaretUp } from 'react-icons/fa6';

type ListProps = {
  title: string;
  content: string;
};

export const List = (props: ListProps) => {
  const { title, content } = props;
  const [isShow, setIsShow] = useState(false);

  const ref1 = useSpringRef();
  const ref2 = useSpringRef();

  const heightStyle = useSpring({
    ref: ref1,
    config: { duration: 100 },
  });

  const fadeStyles = useSpring({
    ref: ref2,
    gridTemplateRows: isShow ? '1fr' : '0fr',
  });

  useChain([ref1, ref2], [0, 0.1]);

  return (
    <animated.div
      className="flex w-full flex-col gap-2 border-y-2 border-main/30 py-2 text-main hover:cursor-pointer md:py-4"
      style={heightStyle}
      onClick={() => setIsShow((value) => !value)}
    >
      <h2 className="flex items-center justify-between text-2xl md:text-4xl">
        {title}
        {isShow ? <FaCaretDown /> : <FaCaretUp />}
      </h2>
      <animated.div className="grid w-full text-xl md:text-2xl" style={fadeStyles}>
        <div className="overflow-hidden">{content}</div>
      </animated.div>
    </animated.div>
  );
};

grid-template-rowsは子要素の高さを設定するCSSプロパティになります。以下にイメージを貼っておきます。

React Springを用いてgrid-template-rowsを使用してアニメーションを実装する場合の概念図

子要素にoverflow:hiddenを付与しておくことで、親要素の大きさによって隠れたり現れたりを実装することができます。実際に赤色内の子要素に関しては、大きさが変わっていません。

実際の変動部分よりもう一段大きく、animated.divで囲んでuseChainで連鎖させることで外枠も連動して動作させています。

終わり

アコーディオンって実装するの結構大変だったんですよね。公式が提供しているサンプルだと、要素の高さを計算していました。maxHeightだと動きがぎこちなくなるという問題があります。海外ニキがサンプルコードを上げてくれているおかげで発見することができました。やはり、フロント界隈の情報は、英語で検索するに限りますね。

React Springに関係する記事を連投することができたので、大満足ですね。こちらのサイトをちょっと良くカスタマイズすることができたので、『アニメーションで始めるプチUX改善』という内容で取り組んでいきたいところです。

これまでのReact Springの記事は以下になります。次は、PythonのTkinter関連の記事でもまとめようと思います。

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です