Click files to view code →
Build a component that toggles the visibility of content. This pattern is commonly used for collapsible sections, FAQs, accordions, and any scenario where you want to conditionally display content based on user interaction.
[!TIP] Goal
Use React's
useState[!IMPORTANT] Requirements
No external dependencies required.
Key Topics:
&&Plan of Action:
ShowHideuseState(false)import React, { useState } from 'react';
import './ShowHide.css';
function ShowHide({
title = "Show More",
children,
initialVisible = false
}) {
const [isVisible, setIsVisible] = useState(initialVisible);
const toggleVisibility = () => {
setIsVisible(!isVisible);
};
return (
<div className="showhide-container">
<button
className="toggle-button"
onClick={toggleVisibility}
aria-expanded={isVisible}
aria-controls="content-section"
>
<span>{isVisible ? 'Hide' : 'Show'} {title}</span>
<span className={`arrow ${isVisible ? 'up' : 'down'}`}>
{isVisible ? '▲' : '▼'}
</span>
</button>
<div
id="content-section"
className={`content ${isVisible ? 'visible' : 'hidden'}`}
aria-hidden={!isVisible}
>
<div className="content-inner">
{children}
</div>
</div>
</div>
);
}
export default ShowHide;CSS Styling (ShowHide.css):
.showhide-container {
width: 100%;
max-width: 600px;
margin: 1rem auto;
font-family: Arial, sans-serif;
}
.toggle-button {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 1.25rem;
background-color: #f5f5f5;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 1rem;
font-weight: 600;
color: #333;
cursor: pointer;
transition: all 0.3s ease;
outline: none;
}
.toggle-button:hover {
background-color: #e8e8e8;
border-color: #2196f3;
}
.toggle-button:focus {
box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.3);
}
.arrow {
font-size: 0.875rem;
transition: transform 0.3s ease;
color: #2196f3;
}
.arrow.up {
transform: rotate(0deg);
}
.arrow.down {
transform: rotate(0deg);
}
.content {
overflow: hidden;
transition: max-height 0.4s ease, opacity 0.3s ease, padding 0.3s ease;
// ...Usage Examples:
import React from 'react';
import ShowHide from './ShowHide';
function App() {
return (
<div className="app">
<h1>FAQ Section</h1>
<ShowHide title="Details" initialVisible={false}>
<p>
This is the hidden content that will be revealed when the button is clicked.
You can put any content here, including text, images, forms, or other components.
</p>
</ShowHide>
<ShowHide title="Shipping Information">
<div>
<h3>Shipping Options</h3>
<ul>
<li>Standard Shipping: 5-7 business days</li>
<li>Express Shipping: 2-3 business days</li>
<li>Overnight Shipping: Next business day</li>
</ul>
</div>
</ShowHide>
<ShowHide title="More Info" initialVisible={true}>
<p>This section is visible by default.</p>
</ShowHide>
</div>
);
}Advanced Version with Read More:
import React, { useState } from 'react';
import './ShowHide.css';
function ReadMore({
text,
maxLength = 150,
showMoreText = "Read more",
showLessText = "Read less"
}) {
const [isExpanded, setIsExpanded] = useState(false);
// Determine if text needs truncation
const needsTruncation = text.length > maxLength;
const displayText = isExpanded || !needsTruncation
? text
: `${text.slice(0, maxLength)}...`;
if (!needsTruncation) {
return <p>{text}</p>;
}
return (
<div className="read-more-container">
<p className="read-more-text">{displayText}</p>
<button
className="read-more-button"
onClick={() => setIsExpanded(!isExpanded)}
>
{isExpanded ? showLessText : showMoreText}
</button>
</div>
);
}
export default ReadMore;Best Practices:
Common Pitfalls:
display: noneEnhancements:
Accordion Component (Multiple Sections):
import React, { useState } from 'react';
function Accordion({ items }) {
const [openIndex, setOpenIndex] = useState(null);
const toggleSection = (index) => {
setOpenIndex(openIndex === index ? null : index);
};
return (
<div className="accordion">
{items.map((item, index) => (
<div key={index} className="accordion-item">
<button
className="accordion-header"
onClick={() => toggleSection(index)}
aria-expanded={openIndex === index}
>
{item.title}
<span className="icon">{openIndex === index ? '−' : '+'}</span>
</button>
{openIndex === index && (
<div className="accordion-content">
{item.content}
</div>
)}
</div>
))}
</div>
);
}
// Usage
function App() {
const faqItems = [
{
title: "What is React?",
content: "React is a JavaScript library for building user interfaces."
},
{
title: "What are React Hooks?",
content: "Hooks are functions that let you use state and lifecycle features in functional components."
},
{
title: "What is JSX?",
content: "JSX is a syntax extension for JavaScript that looks similar to HTML."
}
];
// ...Controlled Component Pattern:
// Controlled version where parent manages state
function ShowHide({ isVisible, onToggle, title, children }) {
return (
<div className="showhide-container">
<button onClick={onToggle} aria-expanded={isVisible}>
{isVisible ? 'Hide' : 'Show'} {title}
</button>
{isVisible && <div className="content">{children}</div>}
</div>
);
}
// Usage
function Parent() {
const [sectionVisible, setSectionVisible] = useState(false);
return (
<ShowHide
isVisible={sectionVisible}
onToggle={() => setSectionVisible(!sectionVisible)}
title="Details"
>
<p>Content here</p>
</ShowHide>
);
}Testing Considerations:
Real-World Use Cases:
This show/hide pattern is one of the most versatile components in UI development and forms the foundation for more complex disclosure widgets.
No files open
Click a file in the explorer to view