Los menús acordeón tienen varios usos como, por ejemplo, mostrar una lista de preguntas frecuentes, o menús y sub-menús, o también las distintas sucursales de un empresa, etc.
En este artículo, veremos cómo hacer un menú acordeón en React, completamente desde cero, paso por paso y sin usar librerías externas.
Usaremos la sintaxis de React Hooks para hacer esta aplicación en React. Por lo que si no estás muy familiarizado con React Hooks, puedes dar un vistazo a mi artículo Introducción a React Hooks [en inglés] para aprender los fundamentos de Hooks.
Puedes ver la demo de la aplicación aquí.
Empecemos.
Configuración inicial del proyecto
Crea un nuevo proyecto create-react-app
.
npx create-react-app react-accordion-demo
Una vez que el proyecto está creado, borra todos los archivos de la carpeta src
y crea los archivos index.js
, App.js
y styles.css
dentro de ella. También crea aquí una nueva carpeta llamada utils
.
Abre el archivo styles.css
y copia este código en ese archivo.
Cómo crear las primeras páginas
Abre el archivo src/App.js
y añade el siguiente código dentro de él:
import React from 'react';
const App = () => {
const accordionData = {
title: 'Section 1',
content: `Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis sapiente
laborum cupiditate possimus labore, hic temporibus velit dicta earum
suscipit commodi eum enim atque at? Et perspiciatis dolore iure
voluptatem.`
};
const { title, content } = accordionData;
return (
<React.Fragment>
<h1>React Accordion Demo</h1>
<div className="accordion">
<div className="accordion-item">
<div className="accordion-title">
<div>{title}</div>
<div>+</div>
</div>
<div className="accordion-content">{content}</div>
</div>
</div>
</React.Fragment>
);
};
export default App;
Aquí usamos las propiedades del objeto accordionData
para mostrar el contenido del acordeón.
Para la propiedad content
, usamos la sintaxis de la plantilla literal de ES6 (``) así podemos escribir en varias líneas. También usamos un texto lorem ipsum de ejemplo.
Luego, abre el archivo src/index.js
y añade el siguiente contenido:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './styles.css';
ReactDOM.render(<App />, document.getElementById('root'));
Si ejecutas la aplicación usando el comando yarn start
desde la terminal, verás la siguiente pantalla:

Cómo abrir y cerrar el menú acordeón
Como has podido ver arriba, pudimos mostrar un única sección como parte del menú acordeón. Por defecto el acordeón está abierta, pero no podemos cerrarlo. Así que vamos a agregar esa funcionalidad para abrirlo y cerrarlo.
Añade un nuevo estado dentro del componente como se muestra a continuación:
const [isActive, setIsActive] = useState(false);
Aquí hemos definido el estado isActive
. Con esto, ocultaremos o mostraremos el contenido del acordeón.
También importa el hook useState
al comienzo del archivo:
import React, { useState } from 'react';
Luego, para el div
con la clase accordion-title
, añade el handler onClick
de la siguiente manera:
<div className="accordion">
<div className="accordion-item">
<div
className="accordion-title"
onClick={() => setIsActive(!isActive)}
>
<div>{title}</div>
<div>{isActive ? '-' : '+'}</div>
</div>
{isActive && <div className="accordion-content">{content}</div>}
</div>
</div>
Aquí estamos invirtiendo el valor del estado isActive
cuando hacemos clic en el div accordion-title
. Si el valor de isActive
es false
, lo ponemos en true
y al revés.
Mostramos el signo +
o -
de acuerdo con el valor de isActive
a través de un operador ternario.
Y si el valor del estado isActive
es true
entonces sólo vamos a mostrar el contenido del acordeón como en el ejemplo de abajo:
{isActive && <div className="accordion-content">{content}</div>}
Si actualizas la aplicación, verás la siguiente pantalla:

Al hacer clic en el título, el acordeón se abre y podemos volver a hacer clic sobre él para cerrarlo.
Cómo añadir varias secciones a un menú acordeón
Si tenemos varias secciones, copiar y pegar una y otra vez el mismo código JSX no funcionará tan bien como si tenemos un solo una sección.
Entonces, lo que vamos a hacer es crear un componente separado solamente para mostrar el acordeón. Luego, de acuerdo con la cantidad de secciones que tengamos, vamos a usar un bucle para recorrer el componente y así hacer que muestre varias secciones.
Crea un nuevo archivo llamado Accordion.js
dentro de la carpeta src
y luego añade el siguiente código dentro de este:
import React, { useState } from 'react';
const Accordion = ({ title, content }) => {
const [isActive, setIsActive] = useState(false);
return (
<div className="accordion-item">
<div className="accordion-title" onClick={() => setIsActive(!isActive)}>
<div>{title}</div>
<div>{isActive ? '-' : '+'}</div>
</div>
{isActive && <div className="accordion-content">{content}</div>}
</div>
);
};
export default Accordion;
Aquí, lo que hemos hecho es mover el estado y el div accordion-item
del archivo App.js
al archivo Accordion.js
. Luego, pasamos las propiedades dinámicas title
y content
usando la sintaxis de desestructuración de ES6:
const Accordion = ({ title, content }) => {
Ahora, abrimos el archivo App.js
y reemplazamos el código con este:
import React from 'react';
import Accordion from './Accordion';
const App = () => {
const accordionData = [
{
title: 'Section 1',
content: `Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis sapiente
laborum cupiditate possimus labore, hic temporibus velit dicta earum
suscipit commodi eum enim atque at? Et perspiciatis dolore iure
voluptatem.`
},
{
title: 'Section 2',
content: `Lorem ipsum, dolor sit amet consectetur adipisicing elit. Mollitia veniam
reprehenderit nam assumenda voluptatem ut. Ipsum eius dicta, officiis
quaerat iure quos dolorum accusantium ducimus in illum vero commodi
pariatur? Impedit autem esse nostrum quasi, fugiat a aut error cumque
quidem maiores doloremque est numquam praesentium eos voluptatem amet!
Repudiandae, mollitia id reprehenderit a ab odit!`
},
{
title: 'Section 3',
content: `Sapiente expedita hic obcaecati, laboriosam similique omnis architecto ducimus magnam accusantium corrupti
quam sint dolore pariatur perspiciatis, necessitatibus rem vel dignissimos
dolor ut sequi minus iste? Quas?`
}
];
return (
<div>
<h1>React Accordion Demo</h1>
<div className="accordion">
{accordionData.map(({ title, content }) => (
<Accordion title={title} content={content} />
))}
</div>
</div>
);
};
export default App;
Lo que hicimos fue convertir el objeto accordionData
en un arreglo de objetos. Luego, lo recorremos con un bucle usando el método map
, además de pasarle las propiedades title
y content
al componente Accordion
.
Si actualizas la aplicación, verás que se muestran las tres secciones y que podemos abrir y cerrar cada una de ellas:

Cómo refactorizar el código
Como has visto, con solo mover la sección del acordeón a un componente separado y pasar el contenido dinámico mediante props, pudimos crear un acordeón desde cero y que funciona.
Como es una buena práctica dejar la información estática en un archivo separado, vamos a mover el arreglo accordionData
a un archivo distinto y luego importarlos desde App.js
Crea un nuevo archivo llamado content.js
dentro de la carpeta utils
y copia el siguiente código dentro de este:
export const accordionData = [
{
title: 'Section 1',
content: `Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis sapiente
laborum cupiditate possimus labore, hic temporibus velit dicta earum
suscipit commodi eum enim atque at? Et perspiciatis dolore iure
voluptatem.`
},
{
title: 'Section 2',
content: `Lorem ipsum, dolor sit amet consectetur adipisicing elit. Mollitia veniam
reprehenderit nam assumenda voluptatem ut. Ipsum eius dicta, officiis
quaerat iure quos dolorum accusantium ducimus in illum vero commodi
pariatur? Impedit autem esse nostrum quasi, fugiat a aut error cumque
quidem maiores doloremque est numquam praesentium eos voluptatem amet!
Repudiandae, mollitia id reprehenderit a ab odit!`
},
{
title: 'Section 3',
content: `Sapiente expedita hic obcaecati, laboriosam similique omnis architecto ducimus magnam accusantium corrupti
quam sint dolore pariatur perspiciatis, necessitatibus rem vel dignissimos
dolor ut sequi minus iste? Quas?`
}
];
Ahora, abre App.js
y reemplaza el código de ese archivo con este:
import React from 'react';
import Accordion from './Accordion';
import { accordionData } from './utils/content';
const App = () => {
return (
<div>
<h1>React Accordion Demo</h1>
<div className="accordion">
{accordionData.map(({ title, content }) => (
<Accordion title={title} content={content} />
))}
</div>
</div>
);
};
export default App;
Con esto hemos importado la información estática desde un archivo externo y luego lo borramos del archivo App.js
.
Entonces ahora el código se ve prolijo y fácil de leer, además de que continúa funcionando:

Cierre
Con esto, hemos terminado de hacer nuestra app.
Puedes encontrar el código completo de esta aplicación en este repositorio de GitHub.
¡Gracias por leer!
Si quieres aprender en detalle todo lo nuevo de ES6+, incluyendo let y const, promesas, distintos métodos de promesas, desestructuración de objetos y arreglos, funciones flecha, async/await, importar y exportar, y mucho más desde cero, dale un vistazo a mi libro Mastering Modern JavaScript. Este libro cubre todo lo necesario para aprender React y ayudarte a mejorar tanto en JavaScript como en React.
