Details Summary

Disclosure

Native HTML details/summary with custom styling.

Preview

Usage

example.jsx
import { DetailsSummary } from "@/components/ui/details-summary";

export default function Example() {
  return <DetailsSummary />;
}

Source Code

Copy this file into components/ui/details-summary.jsx in your project.

details-summary.jsx
"use client";

import { forwardRef, useState } from "react";
import { cn } from "@/lib/utils";

const DetailsSummary = forwardRef(({ className, summary, children, defaultOpen = false, ...props }, ref) => {
  const [open, setOpen] = useState(defaultOpen);
  return (
    <div ref={ref} className={cn("rounded-md border", className)} {...props}>
      <button onClick={() => setOpen(!open)}
        className="flex w-full items-center gap-2 p-3 text-sm font-medium hover:bg-accent/50"
      >
        <svg className={cn("h-4 w-4 shrink-0 transition-transform", open && "rotate-90")} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" /></svg>
        {summary}
      </button>
      {open && <div className="border-t p-3 text-sm text-muted-foreground">{children}</div>}
    </div>
  );
});
DetailsSummary.displayName = "DetailsSummary";

export { DetailsSummary };

Quick Install

Make sure you have the cn() utility set up. It requires clsx and tailwind-merge.

npm install clsx tailwind-merge