Created
October 28, 2025 07:30
-
-
Save mustafadalga/e133b9d6077954d1d9a19854defd160f to your computer and use it in GitHub Desktop.
React Accordion with Smooth Transition
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { useEffect, useRef, useState } from "react"; | |
| const list = [ | |
| { | |
| id: "1", | |
| title: "HTML", | |
| context: "The HyperText Markup Language or HTML is the standard markup language for documents designed to be displayed in a web browser." | |
| }, | |
| { | |
| id: "2", | |
| title: "CSS", | |
| context: "Cascading Style Sheets is a style sheet language used for describing the presentation of a document written in a markup language such as HTML or XML." | |
| }, | |
| { | |
| id: "3", | |
| title: "JavaScript", | |
| context: "JavaScript, often abbreviated as JS, is a programming language that is one of the core technologies of the World Wide Web, alongside HTML and CSS." | |
| } | |
| ] | |
| export function Accordion() { | |
| const [ accordion, setAccordion ] = useState<string[]>(list.map(item => item.id)) | |
| console.log(accordion) | |
| const toggle = (id: string) => { | |
| setAccordion(prev => { | |
| if (prev.includes(id)) { | |
| return prev.filter(row => row != id) | |
| } | |
| return [ ...prev, id ] | |
| }) | |
| } | |
| return ( | |
| <div> | |
| {list.map(item => <AccordionItem key={item.id} | |
| item={item} | |
| isOpen={accordion.includes(item.id)} | |
| toggle={toggle}/>)} | |
| </div> | |
| ); | |
| } | |
| function AccordionItem({ item, isOpen, toggle }) { | |
| const contentRef = useRef<HTMLDivElement>(null); | |
| const [ height, setHeight ] = useState(0) | |
| console.log(contentRef.current?.scrollHeight) | |
| useEffect(() => { | |
| if (contentRef.current) { | |
| setHeight(contentRef.current.scrollHeight) | |
| } | |
| }, []) | |
| useEffect(() => { | |
| if (contentRef.current) { | |
| setHeight(isOpen ? contentRef.current?.scrollHeight : 0) | |
| } | |
| }, [ isOpen ]) | |
| return ( | |
| <div> | |
| <div | |
| onClick={() => toggle(item.id)} | |
| style={{ cursor: "pointer", display: "flex", alignItems: "center" }} | |
| > | |
| {item.title} | |
| <span | |
| style={{ | |
| display: 'inline-block', | |
| marginLeft: '0.5rem', | |
| transition: 'transform 0.3s', | |
| transform: isOpen ? 'rotate(90deg)' : 'rotate(0deg)', | |
| }} | |
| > | |
| ▶ | |
| </span> | |
| </div> | |
| <div | |
| style={{ | |
| overflow: 'hidden', | |
| transition: 'all 0.3s ease-in', | |
| height, | |
| }} | |
| ref={contentRef} | |
| > | |
| <div style={{ padding: '0.5rem' }}>{item.context}</div> | |
| </div> | |
| </div> | |
| ); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment