shadimage
brut-ui
uiaccordionsource: ok · hit

Accordion

The BRUT/UI Accordion component with the current shadcn behavior and API.

npx shadcn add "https://www.brut-ui.site/r/accordion.json"
free

Interaction

accordion

Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.

Dependencies

Bundle weight · light
ui-primitives@base-ui/react
iconslucide-react

Registry dependencies

utils

Files2 · source cached 10/8/2026, 8:17:31 PM

registry/brutalist/ui/accordion.tsx
import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion"

import { cn } from "@/lib/utils"
import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"
import "../styles/brutalist.css"

function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {
  return (
    <AccordionPrimitive.Root
      data-slot="accordion"
      className={cn("flex w-full flex-col", className)}
      {...props}
    />
  )
}

function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {
  return (
    <AccordionPrimitive.Item
      data-slot="accordion-item"
      className={cn("brut-accordion-item", className)}
      {...props}
    />
  )
}

function AccordionTrigger({
  className,
  children,
  ...props
}: AccordionPrimitive.Trigger.Props) {
  return (
    <AccordionPrimitive.Header className="flex">
      <AccordionPrimitive.Trigger
        data-slot="accordion-trigger"
        className={cn(
          "group/accordion-trigger brut-focus relative flex flex-1 items-start justify-between rounded-[var(--radius)] py-3 text-left text-sm font-[var(--brut-weight)] transition-all outline-none hover:underline aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground",
          className
        )}
        {...props}
      >
        {children}
        <ChevronDownIcon data-slot="accordion-trigger-icon" className="pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden" />
        <ChevronUpIcon data-slot="accordion-trigger-icon" className="pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline" />
      </AccordionPrimitive.Trigger>
    </AccordionPrimitive.Header>
  )
}

function AccordionContent({
  className,
  children,
  ...props
}: AccordionPrimitive.Panel.Props) {
  return (
    <AccordionPrimitive.Panel
      data-slot="accordion-content"
      className="overflow-hidden text-sm data-open:animate-accordion-down data-closed:animate-accordion-up"
      {...props}
    >
      <div
        className={cn(
          "h-(--accordion-panel-height) pt-0 pb-2.5 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4",
          className
        )}
      >
        {children}
      </div>
    </AccordionPrimitive.Panel>
  )
}

export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
registry/brutalist/styles/brutalist.css
:root,
[data-brut-palette="paper"] {
  --background: oklch(0.985 0.004 95);
  --foreground: oklch(0.15 0.01 65);
  --card: oklch(1 0 0);
  --card-foreground: var(--foreground);
  --popover: oklch(1 0 0);
  --popover-foreground: var(--foreground);
  --primary: oklch(0.82 0.18 88);
  --primary-foreground: oklch(0.13 0.01 70);
  --secondary: oklch(0.88 0.105 210);
  --secondary-foreground: oklch(0.13 0.01 70);
  --muted: oklch(0.94 0.018 90);
  --muted-foreground: oklch(0.38 0.02 65);
  --accent: oklch(0.72 0.2 20);
  --accent-foreground: oklch(0.99 0 0);
  --destructive: oklch(0.61 0.24 28);
  --border: oklch(0.15 0.01 65);
  --input: oklch(0.15 0.01 65);
  --ring: oklch(0.56 0.23 264);
  --brut-shadow-color: oklch(0.15 0.01 65);
}

:root {
  --chart-1: var(--primary);
  --chart-2: var(--secondary);
  --chart-3: var(--accent);
  --chart-4: var(--destructive);
  --chart-5: var(--muted-foreground);
  --sidebar: var(--card);
  --sidebar-foreground: var(--card-foreground);
  --sidebar-primary: var(--primary);
  --sidebar-primary-foreground: var(--primary-foreground);
  --sidebar-accent: var(--accent);
  --sidebar-accent-foreground: var(--accent-foreground);
  --sidebar-border: var(--border);
  --sidebar-ring: var(--ring);
}

[data-brut-palette="signal"] {
  --background: oklch(0.91 0.16 96);
  --foreground: oklch(0.13 0.01 70);
  --card: oklch(0.985 0.025 96);
  --card-foreground: var(--foreground);
  --popover: oklch(0.985 0.025 96);
  --popover-foreground: var(--foreground);
  --primary: oklch(0.15 0.01 70);
  --primary-foreground: oklch(0.93 0.17 96);
  --secondary: oklch(0.73 0.2 28);
  --secondary-foreground: oklch(0.13 0.01 70);
  --muted: oklch(0.86 0.11 96);
  --muted-foreground: oklch(0.31 0.03 70);
  --accent: oklch(0.75 0.13 222);
  --accent-foreground: oklch(0.13 0.01 70);
  --destructive: oklch(0.55 0.24 28);
  --border: oklch(0.13 0.01 70);
  --input: oklch(0.13 0.01 70);
  --ring: oklch(0.55 0.24 28);
  --brut-shadow-color: oklch(0.13 0.01 70);
}

[data-brut-palette="sky"] {
  --background: oklch(0.92 0.055 235);
  --foreground: oklch(0.16 0.04 255);
  --card: oklch(0.98 0.018 230);
  --card-foreground: var(--foreground);
  --popover: oklch(0.985 0.018 230);
  --popover-foreground: var(--foreground);
  --primary: oklch(0.52 0.2 255);
  --primary-foreground: oklch(0.99 0 0);
  --secondary: oklch(0.88 0.16 92);
  --secondary-foreground: oklch(0.16 0.04 255);
  --muted: oklch(0.86 0.045 235);
  --muted-foreground: oklch(0.36 0.055 255);
  --accent: oklch(0.71 0.18 28);
  --accent-foreground: oklch(0.16 0.04 255);
  --destructive: oklch(0.56 0.24 27);
  --border: oklch(0.16 0.04 255);
  --input: oklch(0.16 0.04 255);
  --ring: oklch(0.67 0.2 28);
  --brut-shadow-color: oklch(0.16 0.04 255);
}

:root,
[data-brut-strength="soft"] {
  --brut-border: 1px;
  --brut-shadow-x: 2px;
  --brut-shadow-y: 2px;
  --brut-panel-shadow-x: 4px;
  --brut-panel-shadow-y: 4px;
  --brut-slider-track: 2px;
  --brut-hover: -1px;
  --brut-press: 1px;
  --brut-weight: 600;
}

[data-brut-strength="solid"] {
  --brut-border: 2px;
  --brut-shadow-x: 4px;
  --brut-shadow-y: 4px;
  --brut-panel-shadow-x: 7px;
  --brut-panel-shadow-y: 7px;
  --brut-slider-track: 4px;
  --brut-hover: -1px;
  --brut-press: 2px;
  --brut-weight: 700;
}

[data-brut-strength="loud"] {
  --brut-border: 3px;
  --brut-shadow-x: 6px;
  --brut-shadow-y: 6px;
  --brut-panel-shadow-x: 9px;
  --brut-panel-shadow-y: 9px;
  --brut-slider-track: 6px;
  --brut-hover: -2px;
  --brut-press: 3px;
  --brut-weight: 800;
}

:root,
[data-brut-radius="cut"] {
  --radius: 0.375rem;
}

[data-brut-radius="sharp"] {
  --radius: 0rem;
}

[data-brut-radius="chunky"] {
  --radius: 0.875rem;
}

@layer base {
  * {
    border-color: var(--border);
    outline-color: color-mix(in oklab, var(--ring) 60%, transparent);
  }

  html {
    scroll-behavior: smooth;
  }

  body {
    background-color: var(--background);
    color: var(--foreground);
  }

  ::selection {
    background: var(--primary);
    color: var(--primary-foreground);
  }
}

@layer components {
  .brut-panel {
    border: var(--brut-border) solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--brut-panel-shadow-x) var(--brut-panel-shadow-y) 0 var(--brut-shadow-color);
  }

  .brut-surface {
    border: var(--brut-border) solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--brut-shadow-x) var(--brut-shadow-y) 0 var(--brut-shadow-color);
  }

  .brut-control {
    border: var(--brut-border) solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--brut-shadow-x) var(--brut-shadow-y) 0 var(--brut-shadow-color);
    font-weight: var(--brut-weight);
    transition: transform 120ms ease, box-shadow 120ms ease, background-color 120ms ease;
  }

  .brut-control:hover:not(:disabled, [data-disabled]) {
    transform: translate(var(--brut-hover), var(--brut-hover));
    box-shadow: calc(var(--brut-shadow-x) - var(--brut-hover)) calc(var(--brut-shadow-y) - var(--brut-hover)) 0 var(--brut-shadow-color);
  }

  .brut-control:active:not(:disabled, [data-disabled]),
  .brut-control[data-pressed] {
    transform: translate(var(--brut-press), var(--brut-press));
    box-shadow: 0 0 0 var(--brut-shadow-color);
  }

  .brut-quiet {
    border: var(--brut-border) solid transparent;
    border-radius: var(--radius);
    box-shadow: none;
    font-weight: var(--brut-weight);
  }

  .brut-quiet:hover {
    border-color: var(--border);
    background: var(--muted);
  }

  .brut-focus:focus-visible {
    outline: 3px solid var(--ring);
    outline-offset: 3px;
  }

  .brut-input {
    border: var(--brut-border) solid var(--input);
    border-radius: var(--radius);
    background: var(--card);
    box-shadow: var(--brut-shadow-x) var(--brut-shadow-y) 0 var(--brut-shadow-color);
    font-weight: 600;
    transition: box-shadow 120ms ease, transform 120ms ease;
  }

  .brut-input:focus-visible {
    outline: 3px solid var(--ring);
    outline-offset: 2px;
    transform: translate(-1px, -1px);
    box-shadow: calc(var(--brut-shadow-x) + 2px) calc(var(--brut-shadow-y) + 2px) 0 var(--brut-shadow-color);
  }

  .brut-input-group {
    border: var(--brut-border) solid var(--input);
    border-radius: var(--radius);
    background: var(--card);
    box-shadow: var(--brut-shadow-x) var(--brut-shadow-y) 0 var(--brut-shadow-color);
    font-weight: 600;
    transition: box-shadow 120ms ease, transform 120ms ease;
  }

  .brut-input-group:focus-within {
    outline: 3px solid var(--ring);
    outline-offset: 2px;
    transform: translate(-1px, -1px);
    box-shadow: calc(var(--brut-shadow-x) + 2px) calc(var(--brut-shadow-y) + 2px) 0 var(--brut-shadow-color);
  }

  .brut-input-group:has([aria-invalid="true"]) {
    border-color: var(--destructive);
  }

  .brut-input-group:has([aria-invalid="true"]):focus-within {
    outline-color: var(--destructive);
  }

  .brut-otp-group:has([data-active="true"]) {
    outline: 3px solid var(--ring);
    outline-offset: 2px;
    transform: translate(-1px, -1px);
    box-shadow: calc(var(--brut-shadow-x) + 2px) calc(var(--brut-shadow-y) + 2px) 0 var(--brut-shadow-color);
  }

  .brut-otp-group:has([aria-invalid="true"]) {
    border-color: var(--destructive);
  }

  .brut-otp-group:has([aria-invalid="true"]):has([data-active="true"]) {
    outline-color: var(--destructive);
  }

  .brut-chip {
    border: var(--brut-border) solid var(--border);
    border-radius: calc(var(--radius) * 0.75);
    box-shadow: none;
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: uppercase;
  }

  .brut-toggle {
    border: var(--brut-border) solid var(--border);
    border-radius: var(--radius);
    box-shadow: none;
    font-weight: var(--brut-weight);
  }

  .brut-kbd {
    border: var(--brut-border) solid var(--border);
    border-radius: calc(var(--radius) * 0.6);
    box-shadow: none;
    font-weight: var(--brut-weight);
  }

  .brut-item {
    border: var(--brut-border) solid var(--border);
    border-radius: var(--radius);
    box-shadow: none;
  }

  .brut-accordion-item:not(:last-child) {
    border-bottom: var(--brut-border) solid var(--border);
    box-shadow: none;
  }

  .brut-check {
    border: var(--brut-border) solid var(--border);
    border-radius: calc(var(--radius) * 0.5);
    background: var(--card);
    box-shadow: 2px 2px 0 var(--brut-shadow-color);
  }

  .brut-radio {
    border: var(--brut-border) solid var(--input);
  }

  .brut-slider-thumb {
    border: var(--brut-border) solid var(--ring);
  }

  .brut-menubar {
    border: var(--brut-border) solid var(--border);
  }

  .brut-avatar {
    border: var(--brut-border) solid var(--border);
    background: var(--card);
    box-shadow: calc(var(--brut-border) + 1px) calc(var(--brut-border) + 1px) 0 var(--brut-shadow-color);
  }

  .brut-separator {
    background: var(--border);
  }

  .brut-dialog {
    border: var(--brut-border) solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--brut-panel-shadow-x) var(--brut-panel-shadow-y) 0 var(--brut-shadow-color);
  }

  .brut-questionnaire-choice {
    border: var(--brut-border) solid var(--input);
    border-radius: var(--radius);
  }

  .brut-sheet[data-side="right"] {
    border-left: var(--brut-border) solid var(--border);
    border-radius: var(--radius) 0 0 var(--radius);
    box-shadow: calc(0px - var(--brut-panel-shadow-x)) 0 0 var(--brut-shadow-color);
  }

  .brut-sheet[data-side="left"] {
    border-right: var(--brut-border) solid var(--border);
    border-radius: 0 var(--radius) var(--radius) 0;
    box-shadow: var(--brut-panel-shadow-x) 0 0 var(--brut-shadow-color);
  }

  .brut-sheet[data-side="bottom"] {
    border-top: var(--brut-border) solid var(--border);
    border-radius: var(--radius) var(--radius) 0 0;
    box-shadow: 0 calc(0px - var(--brut-panel-shadow-y)) 0 var(--brut-shadow-color);
  }

  .brut-sheet[data-side="top"] {
    border-bottom: var(--brut-border) solid var(--border);
    border-radius: 0 0 var(--radius) var(--radius);
    box-shadow: 0 var(--brut-panel-shadow-y) 0 var(--brut-shadow-color);
  }

  .brut-drawer[data-swipe-direction="down"] {
    border-top: var(--brut-border) solid var(--border);
    border-radius: var(--radius) var(--radius) 0 0;
    box-shadow: 0 calc(0px - var(--brut-panel-shadow-y)) 0 var(--brut-shadow-color);
  }

  .brut-drawer[data-swipe-direction="up"] {
    border-bottom: var(--brut-border) solid var(--border);
    border-radius: 0 0 var(--radius) var(--radius);
    box-shadow: 0 var(--brut-panel-shadow-y) 0 var(--brut-shadow-color);
  }

  .brut-drawer[data-swipe-direction="left"] {
    border-right: var(--brut-border) solid var(--border);
    border-radius: 0 var(--radius) var(--radius) 0;
    box-shadow: var(--brut-panel-shadow-x) 0 0 var(--brut-shadow-color);
  }

  .brut-drawer[data-swipe-direction="right"] {
    border-left: var(--brut-border) solid var(--border);
    border-radius: var(--radius) 0 0 var(--radius);
    box-shadow: calc(0px - var(--brut-panel-shadow-x)) 0 0 var(--brut-shadow-color);
  }

  .brut-popover {
    border: var(--brut-border) solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--brut-shadow-x) var(--brut-shadow-y) 0 var(--brut-shadow-color);
  }

  .brut-switch {
    border: var(--brut-border) solid var(--border);
    border-radius: var(--radius);
    box-shadow: 3px 3px 0 var(--brut-shadow-color);
  }

  .brut-switch-thumb {
    border-radius: calc(var(--radius) * 0.75);
  }

  .brut-progress {
    border: var(--brut-border) solid var(--border);
    border-radius: var(--radius);
    background: var(--card);
  }

  .brut-resizable-group {
    overflow: hidden;
    border: var(--brut-border) solid var(--border);
    border-radius: var(--radius);
    background: var(--card);
  }

  .brut-resizable-handle {
    width: var(--brut-border);
    background: var(--border);
  }

  .brut-resizable-handle[aria-orientation="horizontal"] {
    width: 100%;
    height: var(--brut-border);
  }

  .brut-resizable-grip {
    border: var(--brut-border) solid var(--border);
    border-radius: min(var(--radius), 0.375rem);
    background: var(--card);
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    scroll-behavior: auto !important;
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
}

More from brut-ui

Browse all components in this library →