アコーディオンメニューの作り方[後編]

こんにちは、いすいです。

本日は、アコーディオンメニューの作り方の後編です。

前編では、html だけを使ったもの、html/css/javascript を使ったもの、

bootstrapを使ったものをご紹介しました。

後編では、React を使った方法をご紹介します。

前編の内容

React を使った方法

以降では、React の基本は知っているという前提で進めます。

参考サイト

onebitious’s BLOGさんの記事を参考にさせてもらっています。

使うライブラリ

React にはアコーディオンのためのライブラリが用意されています。

それが react-accessible-accordion です。

https://github.com/springload/react-accessible-accordion

最初はあれこれコードを試行錯誤するとは思うのですが、

react-accessible-accordion実装のしやすさ、スタイルの当てやすさ、コードの可読性、それらがちょうど良いライブラリだと思います。

ライブラリをインストールするには以下を実行します。

npm install react-accessible-accordion

実装

今回コンポーネントは2つ作成します。

  1. アコーディオンメニュー(全体)
  2. アコーディオンコンポーネント

データ

アコーディオンに入れるデータは以下のようなものを用意してください。

[
    {
        "id": 1,
        "name": "テストA",
        "children": [
            {
                "id": 2,
                "name": "テストB",
                "children": [
                    {
                        "id": 3,
                        "name": "テストC",
                        "children": [
                            {
                                "id": 4,
                                "name": "テストD",
                                "children": null
                            }
                        ]
                    }
                ]
            }
        ]
    }
]

階層構造となっており、「children」フィールドに子の階層が入ります。

最下層の場合は「children」を null にしています。

「id」は React のリストの「key」に入れるためのものですので、一意であれば値は任意で大丈夫です。

1.アコーディオンメニュー(全体)

アコーディオンメニューの全体のコンポーネントを作成します。

import { AccordionList } from "./AccordionList";


export const AccordionMenu = ({ data }) => {

    return (
        <>
            {data.map((item) => {
                return (
                    <AccordionList item={item} key={item.id} />
                )
            })}
        </>
    );
};

↑↑

AccorionMenu は data を引数として受け取ります。

data の中身は先ほどの「データ」で記載したものです。

data はリストになっているので、要素ごとにアコーディオンを作成します。

2.アコーディオンコンポーネント

続いて、主役アコーディオンのコンポーネントです。

import styled from "styled-components";

import {
    Accordion,
    AccordionItem,
    AccordionItemHeading,
    AccordionItemButton,
    AccordionItemPanel,
} from 'react-accessible-accordion';

// Demo styles, see 'Styles' section below for some notes on use.
import 'react-accessible-accordion/dist/fancy-example.css';

export const AccordionList = ({ item }) => {
    return (
        <>
            {item.children == null ? (
                <span>{item.name}</span>
            ) : (
                <Accordion allowZeroExpanded>
                    <AccordionItem>
                        <AccordionItemHeading>
                            <AccordionItemButton>
                                {item.name}
                            </AccordionItemButton>
                        </AccordionItemHeading>
                        <AccordionItemPanel>
                            {item.children.map((child) => {
                                return (
                                    <AccordionList item={child} key={child.id} />
                                )
                            })}
                        </AccordionItemPanel>
                    </AccordionItem>
                </Accordion>
            )}
        </>
    );
};

↑↑

このコードは、再帰的に「children」を掘っていってアコーディオンを作成します。

import {
    Accordion,
    AccordionItem,
    AccordionItemHeading,
    AccordionItemButton,
    AccordionItemPanel,
} from 'react-accessible-accordion';

↑↑

ここで react-accessible-accordion のクラス群をインポートします。

       {item.children == null ? (
                <span>{item.name}</span>
            ) : (
              <省略>
            )

↑↑

ここは、要素の「children」フィールドが null かどうかを判断しています。

null の場合、最下層なのでそのまま「name」フィールドを表示するようにしています。

               <Accordion allowZeroExpanded>
                    <AccordionItem>
                        <AccordionItemHeading>
                            <AccordionItemButton>
                                {item.name}
                            </AccordionItemButton>
                        </AccordionItemHeading>
                        <AccordionItemPanel>
                            {item.children.map((child) => {
                                return (
                                    <AccordionList item={child} key={child.id} />
                                )
                            })}
                        </AccordionItemPanel>
                    </AccordionItem>
                </Accordion>

↑↑

ここでアコーディオンを作成します。

allowZeroExpanded はオプションで、アコーディオンが空でも開けるように許可するものになります。

                        <AccordionItemHeading>
                            <AccordionItemButton>
                                {item.name}
                            </AccordionItemButton>
                        </AccordionItemHeading>↑↑

↑↑

ここの部分がアコーディオンの開閉を行うボタンの部分になります。

                        <AccordionItemPanel>
                            {item.children.map((child) => {
                                return (
                                    <AccordionList item={child} key={child.id} />
                                )
                            })}
                        </AccordionItemPanel>

↑↑

ここがアコーディオンとして開いたり閉じたりするところです。

「children」フィールドを map で回して、自分自身である AccordionList をさらに呼び出しています。

実行してみる

うまく実行できると結構いい感じのアコーディオンメニューが表示されます。

みなさんがアプリで実装する際は、

データやコンポーネントなどカスタマイズしてみてください。

スタイル

さて、次に大事なのは見た目のスタイリングです!

ライブラリのスタイリングってものによっては、あまり自由度がなかったり、スタイリングがむずかしかったりします。

しかし、安心してください。

react-accessible-accordion では結構簡単にスタイリングできます。

なぜかというと、react-accessible-accordion のデフォルトの CSS って短い構成になってるんです。

つまり、デフォルトの CSS を直接編集できちゃいます。

AccordionList.js の12行目にデフォルトの CSS が当たっていますので、

以下のように変更します。(CSS のファイル名はなんでも良いですが、)

// import 'react-accessible-accordion/dist/fancy-example.css';
import './accordion_custom.css';

デフォルトの CSS は以下のリンクにあります。

https://github.com/springload/react-accessible-accordion/blob/main/src/css/fancy-example.css

見てみると本当にコンパクトですよね。😳😳😳

その内容を、「accordion_custom.css」に貼り付けます。

そして色々いじってみてどのようなスタイルが良いか試しみてください。

CSS のクラス名とコンポーネント名は概ね一致しているので、なんとなくわかると思います。

例:accordion__button → AccordionItemButton

以下は私が編集した CSS の例です。

/**
* ----------------------------------------------
* Demo styles
* ----------------------------------------------
**/

.accordion__button {
    color: #fff;
    cursor: pointer;
    width: 100%;
    height: 30px;
    text-align: left;
    border: none;
}

.accordion__button:hover {
    color: #ddd;
}

.accordion__button:before {
    display: inline-block;
    content: '';
    height: 8px;
    width: 8px;
    margin-right: 10px;
    border-bottom: 1px solid #ddd;
    border-right: 1px solid #ddd;
    transform: rotate(-45deg);
    transition: .1s;
}

.accordion__button[aria-expanded='true']::before,
.accordion__button[aria-selected='true']::before {
    transform: rotate(45deg);
    transition: .1s;
}

[hidden] {
    display: none;
}

.accordion__panel {
    animation: fadein 0.2s ease-in;
}

/* -------------------------------------------------- */
/* ---------------- Animation part ------------------ */
/* -------------------------------------------------- */

@keyframes fadein {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

主な変更点としては、以下あたりになります。

  • 余分な Border の削除
  • transition でアコーディオンの開閉をなめらかにする

まとめ

以上、React でのアコーディオンメニューの実装方法をご紹介いたしました。

前編も参考にしていただいて、一番合った方法で実装していただければと思います!

もちろん他にもたくさん方法はあるかと思いますので、

あくまでこういう方法もあるよ、ということで受け取ってもらえれば幸いです。

SNSでもご購読できます。

コメント

コメントを残す

*