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)です。closedIcon
とopenedIcon
は、それぞれ閉じているときと開いているときに表示されるアイコンの 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 の公式サイトでは、既製のアコーディオンコンポーネントを提供しており、その使用方法を詳 |