Cool accordion with React.js.

React accordion

a nice React accordion example.

Made with

Html
Css/SCSS
Javascript

Html

#app

Css

$brown = #f0ebe1
$black = #372717
$gray = #756658

*, *:after, *:before
	box-sizing inherit

body
	display flex
	justify-content center
	padding 50px 0
	background-color #FCFCFC
	min-height 100vh
	font-size 16px
	line-height 1.4
	font-family 'Montserrat', sans-serif
	color $black
	box-sizing border-box
	overflow-y scroll
	
.accordion
	width 100%
	max-width 470px
	
.panel
	background-color $brown
	
	&__label
		position relative
		display block
		width 100%
		background none
		border none
		text-align left
		padding 25px 60px 25px 25px
		font-weight 500
		font-size 17px
		font-family inherit
		transition color .2s linear
		cursor pointer
		
		&:focus
			outline none
		
		&:after,
		&:before
			content ''
			position absolute
			right 25px
			top 50%
			width 22px
			height 2px
			margin-top -@height
			background-color $black
			
		&:before
			transform rotate(-90deg)
			transition transform .35s cubic-bezier(.65, .05, .36, 1)
			
	&[aria-expanded='true']
		
		& ^[0]__content
			opacity 1

		& ^[0]__label
			color #957029
	
			&:before
				transform rotate(0deg)
		
	&__inner
		overflow hidden
		will-change height
		transition height .4s cubic-bezier(.65, .05, .36, 1)
		
	&__content
		margin 5px 25px 25px
		font-size 14px
		color $gray
		opacity 0
		transition opacity .3s linear .18s
		
	&:not(:last-child)
		margin-bottom 3px

Javascript

class Panel extends React.Component {
	constructor(props) {
		super(props);
		
		this.state = {
			height: 0
		};
	}

	componentDidMount() {
		window.setTimeout(() => {
			const el = ReactDOM.findDOMNode(this);
			const height = el.querySelector('.panel__inner').scrollHeight;
			this.setState({
				height
			});
		}, 333);
	}

	render () {
		const { label, content, activeTab, index, activateTab } = this.props;
		const { height } = this.state;
		const isActive = activeTab === index;
		const innerStyle = {
			height: isActive ? `${height}px` : '0px'
		}

		return (
			<div className='panel'
				role='tabpanel'
				aria-expanded={isActive}>
				<button className='panel__label'
					role='tab'
					onClick={activateTab}>
					{label}
				</button>
				<div className='panel__inner'
					style={innerStyle}
					aria-hidden={!isActive}>
					<p className='panel__content'>
						{content}
					</p>
				</div>
			</div>
		);
	}
}

class Accordion extends React.Component {
	constructor(props) {
		super(props);
		
		this.state = {
			activeTab: 0
		};
		
		this.activateTab = this.activateTab.bind(this);
	}
	
	activateTab(index) {
		this.setState(prev => ({
			activeTab: prev.activeTab === index ? -1 : index
		}));
	}
	
	render() {
		const { panels } = this.props;
		const { activeTab } = this.state;
		return (
			<div className='accordion' role='tablist'>
				{panels.map((panel, index) =>
					<Panel
						key={index}
						activeTab={activeTab}
						index={index}
						{...panel} 
						activateTab={this.activateTab.bind(null, index)}
					/>
				)}
			</div>
		);
	}
}

const panels = [
	{
		label: 'Seriously, Don\'t Use Icon Fonts',
		content: 'Icons are everywhere. These "little miracle workers" (as John Hicks described them) help us reinforce meaning in the interfaces we design and build. Their popularity in web design has never been greater; the conciseness and versatility of pictograms in particular make them a lovely fit for displays large and small. But icons on the web have had their fair share of challenges.',
	},
	{
		label: 'Screen Readers Actually Read That Stuff',
		content: 'Most assistive devices will read aloud text inserted via CSS, and many of the Unicode characters icon fonts depend on are no exception. Best-case scenario, your "favorite" icon gets read aloud as "black favorite star." Worse-case scenario, it\'s read as "unpronounceable" or skipped entirely.',
	},	
	{
		label: 'They Fail Poorly and Often',
		content: 'When your icon font fails, the browser treats it like any other font and replaces it with a fallback. Best-case scenario, you\'ve chosen your fallback characters carefully and something weird-looking but communicative still loads. Worse-case scenario (and far more often), the user sees something completely incongruous, usually the dreaded "missing character" glyph.',
	},
	{
		label: 'They\'re a Nightmare if You\'re Dyslexic',
		content: 'Many dyslexic people find it helpful to swap out a website\'s typeface for something like OpenDyslexic. But icon fonts get replaced as well, which makes for a frustratingly broken experience.',
	},
	{
		label: 'There\'s Already a Better Way',
		content: 'SVG is awesome for icons! It\'s a vector image format with optional support for CSS, JavaScript, reusability, accessibility and a bunch more. It was made for this sort of thing.'
	},
];

const App = document.querySelector('#app');

ReactDOM.render(<Accordion panels={panels}/>, App);

Author

DNLHC

Demo

See the Pen React accordion by DNLHC (@DNLHC) on CodePen.