roiui
itemaccordionsource: ok · hit
Accordion
A collapsible content component.
npx shadcn add "https://roiui.com/r/accordion.json"free
Interaction
accordion
Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.
Files2 · source cached 10/9/2026, 8:56:27 AM
registry/brook/ui/accordion/accordion.tsx
"use client";
import { Accordion } from "@base-ui/react/accordion";
import { cn } from "../../../lib/utils";
import styles from "./accordion.module.css";
function AccordionRoot({ className, ...props }: Accordion.Root.Props) {
return <Accordion.Root className={cn(styles.root, className)} data-slot="accordion-root" {...props} />;
}
function AccordionItem({ className, ...props }: Accordion.Item.Props) {
return <Accordion.Item className={cn(styles.item, className)} data-slot="accordion-item" {...props} />;
}
function AccordionHeader({ className, ...props }: Accordion.Header.Props) {
return <Accordion.Header className={cn(styles.header, className)} data-slot="accordion-header" {...props} />;
}
function AccordionTrigger({ className, children, ...props }: Accordion.Trigger.Props) {
return (
<Accordion.Trigger className={cn(styles.trigger, className)} data-slot="accordion-trigger" {...props}>
<div className={styles.icon}>
<svg aria-label="Accordion toggle icon" fill="none" height="18" role="img" viewBox="0 0 20 20" width="18">
<title>Toggle accordion</title>
<path
className={styles.horizontalLine}
d="M4 10L16 10"
stroke="currentColor"
strokeLinecap="round"
strokeWidth="2"
/>
<path d="M10 4L10 16" stroke="currentColor" strokeLinecap="round" strokeWidth="2" />
</svg>
</div>
<div>{children}</div>
</Accordion.Trigger>
);
}
function AccordionPanel({ className, children, ...props }: Accordion.Panel.Props) {
return (
<Accordion.Panel className={cn(styles.panel, className)} data-slot="accordion-panel" {...props}>
<div className={styles.content}>
<div className={styles.contentInner}>{children}</div>
</div>
</Accordion.Panel>
);
}
export { AccordionRoot as Accordion, AccordionHeader, AccordionItem, AccordionPanel, AccordionRoot, AccordionTrigger };
registry/brook/ui/accordion/accordion.module.css
.root {
width: 32rem;
max-width: calc(100vw - 8rem);
display: flex;
flex-direction: column;
}
.item {
overflow: hidden;
background-color: var(--mix-card-75-bg);
padding: 1rem;
border-bottom: 0.5px solid var(--border);
transition:
margin 200ms var(--ease-in-out-quad),
border-radius 200ms var(--ease-in-out-quad),
border-color 200ms var(--ease-in-out-quad);
&:first-child {
border-radius: 1.5rem 1.5rem 0 0;
}
&:last-child {
border-radius: 0 0 1.5rem 1.5rem;
border-bottom-color: transparent;
}
&:first-child:last-child {
border-radius: 1.5rem;
}
&[data-open] {
border-radius: 1.5rem;
margin-top: 0.5rem;
margin-bottom: 0.5rem;
border-bottom-color: transparent;
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
}
&:has(+ .item[data-open]):not([data-open]) {
border-radius: 0 0 1.5rem 1.5rem;
border-bottom-color: transparent;
&:first-child {
border-radius: 1.5rem;
}
}
&[data-open] + &:not([data-open]) {
border-radius: 1.5rem 1.5rem 0 0;
&:last-child {
border-radius: 1.5rem;
}
}
&[data-open] + &:not([data-open]):has(+ .item[data-open]) {
border-radius: 1.5rem;
border-bottom-color: transparent;
}
}
.header {
margin: 0;
}
.icon {
display: flex;
align-items: center;
justify-content: center;
width: 2rem;
height: 2rem;
color: var(--muted-foreground);
transition:
color 200ms ease,
rotate 150ms var(--ease-in-out-quad);
rotate: 0deg;
}
.horizontalLine {
transition:
opacity 150ms var(--ease-in-out-quad),
scale 150ms var(--ease-in-out-quad);
transform-origin: center;
}
.trigger {
display: flex;
width: 100%;
align-items: center;
gap: 1rem;
font-size: 1rem;
line-height: 1.5;
letter-spacing: -0.02em;
font-weight: 350;
text-align: left;
background: transparent;
border: none;
cursor: pointer;
color: var(--secondary-foreground);
&[data-panel-open] .icon {
rotate: 90deg;
}
&:hover .icon {
color: var(--foreground);
}
&[data-panel-open] .horizontalLine {
opacity: 0;
scale: 0;
}
}
.panel {
height: var(--accordion-panel-height);
overflow: hidden;
transition: height 150ms var(--ease-in-out-quad);
&[data-starting-style],
&[data-ending-style] {
height: 0;
}
}
.content {
overflow: hidden;
width: 100%;
}
.contentInner {
margin-left: calc(3rem);
padding-right: 3rem;
font-size: 0.875rem;
line-height: 1.6;
color: oklch(from var(--foreground) l c h / 0.75);
}
@media (max-width: 640px) {
.root {
width: 100%;
max-width: 100%;
}
.item {
padding: 1rem;
}
.trigger {
gap: 0.75rem;
}
.icon {
width: 1.75rem;
height: 1.75rem;
flex-shrink: 0;
& svg {
width: 16px;
height: 16px;
}
}
.contentInner {
margin-left: 2.5rem;
padding-right: 0;
font-size: 0.9375rem;
line-height: 1.5;
}
}