Skip to content

Instantly share code, notes, and snippets.

@rajasegar
Created September 24, 2021 10:23
Show Gist options
  • Save rajasegar/9628b5d3489d6270c6c1b5c35ba5f81f to your computer and use it in GitHub Desktop.
Save rajasegar/9628b5d3489d6270c6c1b5c35ba5f81f to your computer and use it in GitHub Desktop.
Accordion component in React and Typescript using details and summary
import React, { useState } from "react";
import styled from "styled-components";
import { Icons } from "../Icons";
const Content = styled.div`
padding: 1em;
`;
const Summary = styled.summary`
::marker {
display: none;
}
`;
export function Option({ label, children }) {
const [open, setOpen] = useState(false);
return (
<React.Fragment>
<Summary onClick={() => setOpen(!open)}>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<div> {label} </div>
<div>
<Icons glyph={open ? "chevron-up" : "chevron-down"} />
</div>
</div>
</Summary>
<Content>{children}</Content>
</React.Fragment>
);
}
const AccordionWrapper = styled.div`
summary::moz-details-marker {
display: none;
}
summary::webkit-details-marker {
display: none;
}
`;
export const AccordionItem = styled.details.attrs((props) => ({
open: props.open || false,
}))`
background-color: white;
padding: 0.5em;
border-top: 1px solid #eee;
border-bottom: 1px solid #eee;
font-style: inherit;
:hover {
box-shadow: 1px 1px 16px rgba(0, 0, 0, 0.25);
}
summary::-webkit-details-marker,
summary::marker {
display: none;
content: "";
}
`;
type AccordionProps = {
children: React.ReactNode;
};
export function Accordion({ children }: AccordionProps) {
return <AccordionWrapper>{children}</AccordionWrapper>;
}
import React from "react";
import { AccordionItem, Option, Accordion } from "./";
export const Basic = () => {
const openSections = [1];
function getContent(text) {
return <div>{text}</div>;
}
function getOptions(openSections) {
return [];
}
return (
<>
<Accordion>
<AccordionItem open={true}>
<Option label="Section Title One">{getContent("Lorem ipsum")}</Option>
</AccordionItem>
<AccordionItem>
<Option label="Section Title Two">{getContent("Lorem ipsum")}</Option>
</AccordionItem>
<AccordionItem>
<Option label="Section Title Three">
{getContent("Lorem ipsum")}
</Option>
</AccordionItem>
</Accordion>
</>
);
};
export default {
component: Basic,
title: "Accordion",
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment