ども!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プロパティになります。以下にイメージを貼っておきます。
子要素にoverflow:hidden
を付与しておくことで、親要素の大きさによって隠れたり現れたりを実装することができます。実際に赤色内の子要素に関しては、大きさが変わっていません。
実際の変動部分よりもう一段大きく、animated.div
で囲んでuseChain
で連鎖させることで外枠も連動して動作させています。
終わり
アコーディオンって実装するの結構大変だったんですよね。公式が提供しているサンプルだと、要素の高さを計算していました。maxHeight
だと動きがぎこちなくなるという問題があります。海外ニキがサンプルコードを上げてくれているおかげで発見することができました。やはり、フロント界隈の情報は、英語で検索するに限りますね。
React Springに関係する記事を連投することができたので、大満足ですね。こちらのサイトをちょっと良くカスタマイズすることができたので、『アニメーションで始めるプチUX改善』という内容で取り組んでいきたいところです。
これまでのReact Springの記事は以下になります。次は、PythonのTkinter関連の記事でもまとめようと思います。