Next.js と TypeScript で、アコーディオンコンポーネントを作成

TwitterFacebookHatena

TL;DR

Emotion.js の styled を使って、アコーディオンコンポーネントを実装します。

開発環境 バージョン
Next.js 13.4.3
TypeScript 5.0.4
Emotion 11.11.0
React 18.2.0

全体のコード

/components/Animation/Accordion.tsx

import { useState } from 'react'
import styled from '@emotion/styled'

interface AccordionProps {
  title: string
  content: React.ReactNode // ReactNode は、React の要素を表す型
  closedIcon: string
  openedIcon: string
}

const AccordionButton = styled.button`
  width: 100%;
  height: 80px;
  background-color: #f1f1f1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
  border: none;
  cursor: pointer;
  box-sizing: border-box;
  color: black;

  &:focus {
    outline: none;
  }
`

const AccordionIcon = styled.img`
  width: 20px;
  height: 20px;
`

const AccordionContent = styled.div`
  margin-bottom: 20px;
  width: 100%;
  height: 0;
  overflow: hidden;
  background-color: #fff;
  box-sizing: border-box;
  transition: height 0.3s ease-in-out;
  p {
    padding: 24px;
  }
`

const Accordion = ({ title, content, closedIcon, openedIcon }: AccordionProps) => {
  const [isOpen, setIsOpen] = useState(false)

  const toggleAccordion = () => {
    setIsOpen(!isOpen)
  }

  return (
    <div>
      <AccordionButton onClick={toggleAccordion}>
        <span>{title}</span>
        <AccordionIcon src={isOpen ? openedIcon : closedIcon} alt={isOpen ? 'opened' : 'closed'} />
      </AccordionButton>
      <AccordionContent style={{ height: isOpen ? 'auto' : 0 }}>{content}</AccordionContent>
    </div>
  )
}

export default Accordion

呼び出し

// 型定義
import { NextPage, GetStaticProps } from 'next'
// Acordion
import Accordion from 'components/Animation/Accordion'

const Home: NextPage = () => {
  const handleTabClick = (index: number) => {
    console.log(`Tab ${index + 1} is clicked!`)
  }
  return (
    <>
      {/* Accordion */}
      <TTL>Accordion</TTL>
      <Accordion title="Accordion 1" content={<p>Content for Accordion 1 goes here.</p>} closedIcon="./icon/triangle-under.svg" openedIcon="./icon/triangle.svg" />
      <Accordion title="Accordion 2" content={<p>Content for Accordion 2 goes here.</p>} closedIcon="./icon/triangle-under.svg" openedIcon="./icon/triangle.svg" />
      <Accordion title="Accordion 3" content={<p>Content for Accordion 3 goes here.</p>} closedIcon="./icon/triangle-under.svg" openedIcon="./icon/triangle.svg" />
    </>
  )
}

export default Home

解説

上のコードを解説します。

こちらのコードでは、React を使ってアコーディオンコンポーネントを作成しています。styledを使ってスタイリングされたコンポーネントも使用しています。では、一部分ずつ見ていきましょう。

Accordion コンポーネント

interface AccordionProps {
  title: string
  content: React.ReactNode // ReactNode は、React の要素を表す型
  closedIcon: string
  openedIcon: string
}

まずはじめに、Accordion コンポーネントが受け取る props の型を定義しています。title は文字列で、content は React のノード(つまり、何らかの JSX)です。closedIconopenedIconは、それぞれ閉じているときと開いているときに表示されるアイコンの URL を表します。

const [isOpen, setIsOpen] = useState(false)

const toggleAccordion = () => {
  setIsOpen(!isOpen)
}

次に、Accordion コンポーネントの内部状態を表す isOpen を定義しています。これはアコーディオンが開いているか閉じているかを表すブール値です。toggleAccordion 関数は、その値をトグルするためのものです。

return (
  <div>
    <AccordionButton onClick={toggleAccordion}>
      <span>{title}</span>
      <AccordionIcon src={isOpen ? openedIcon : closedIcon} alt={isOpen ? 'opened' : 'closed'} />
    </AccordionButton>
    <AccordionContent style={{ height: isOpen ? 'auto' : 0 }}>{content}</AccordionContent>
  </div>
)

そして、このコンポーネントが返す JSX を定義しています。アコーディオンのタイトルとアイコンが含まれるボタンと、コンテンツ部分があります。ボタンがクリックされると toggleAccordion 関数が呼び出され、アコーディオンが開いたり閉じたりします。また、アイコンとコンテンツ部分の表示は isOpen の値によって変わります。

スタイル付きコンポーネント

このコードでは Emotion の styled 関数を使ってスタイル付きコンポーネントを作成しています。この関数を使うと、通常の React コンポーネントと同じようにスタイル付きコンポーネントを使用できます。これにより CSS の再利用や動的なスタイリングが可能になります。

Home コンポーネント

こちらはアコーディオンコンポーネントを実際に使用している例です。それぞれのアコーディオンに異なるタイトルとコンテンツ、そして同じアイコンを設定しています。これで、このコードの全体像が掴めたかと思います。どうでしょうか?それぞれの部分の役割や働きが理解できましたか?

アコーディオンを学ぶ

ここまで読んで、「もっと詳しく学びたい!」という方は、以下のリンクを参考にしてみてください。

タイトル 説明
Mozilla Developer Network MDN では、基本的な HTML のアコーディオン要素について説明しています。
W3Schools - How TO - Accordion W3Schools では、JavaScript を用いたアコーディオンの基本的な実装方法を紹介しています。
Material-UI: Accordion Material-UI の公式サイトでは、既製のアコーディオンコンポーネントを提供しており、その使用方法を詳

Next.js と TypeScript で、アコーディオンコンポーネントを作成