Installation
Install the required dependencies.
npm install @radix-ui/react-accordion
Copy and paste the following code into your project.
components/ui/sketch-accordion.tsx
"use client";
import * as React from "react";
import * as AccordionPrimitive from "@radix-ui/react-accordion";
import { cn } from "@/lib/utils";
const SketchAccordion = AccordionPrimitive.Root;
const SketchAccordionItem = React.forwardRef<
React.ComponentRef<typeof AccordionPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
>(({ className, ...props }, ref) => (
<AccordionPrimitive.Item
ref={ref}
className={cn(
"group relative mb-2 overflow-hidden rounded-lg border border-neutral-200 bg-white transition-all dark:border-neutral-800 dark:bg-neutral-950",
"before:absolute before:inset-0 before:z-0 before:bg-[url('/paper-texture.png')] before:opacity-50 before:content-['']",
className,
)}
{...props}
/>
));
SketchAccordionItem.displayName = "SketchAccordionItem";
const SketchAccordionTrigger = React.forwardRef<
React.ComponentRef<typeof AccordionPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
ref={ref}
className={cn(
"group/trigger flex flex-1 items-center justify-between py-4 pl-4 pr-2 text-sm font-medium transition-all [&[data-state=open]>svg]:rotate-180",
"after:absolute after:left-0 after:top-0 after:h-full after:w-1 after:bg-neutral-200 after:content-[''] dark:after:bg-neutral-800",
"hover:bg-neutral-50 dark:hover:bg-neutral-900",
className,
)}
{...props}
>
{children}
<div className="relative mr-2 h-5 w-5 shrink-0 overflow-hidden rounded-full border border-neutral-300 dark:border-neutral-700 cursor-pointer">
<svg
className="absolute inset-0 h-4 w-4 translate-x-0.5 translate-y-0.5 stroke-[1.5] transition-transform duration-200"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
style={{
filter: "url(#pencil-stroke)",
}}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M19 9l-7 7-7-7"
/>
</svg>
</div>
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
));
SketchAccordionTrigger.displayName = "SketchAccordionTrigger";
const SketchAccordionContent = React.forwardRef<
React.ComponentRef<typeof AccordionPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Content
ref={ref}
className="overflow-hidden transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
{...props}
>
<div
className={cn(
"relative px-4 pb-4 pt-0",
"after:absolute after:left-0 after:top-0 after:h-full after:w-1 after:bg-neutral-200 after:content-[''] dark:after:bg-neutral-800",
className,
)}
>
{children}
</div>
</AccordionPrimitive.Content>
));
SketchAccordionContent.displayName = "SketchAccordionContent";
// SVG Filter for pencil effect
const PencilFilter = () => (
<svg width="0" height="0">
<defs>
<filter id="pencil-stroke">
<feTurbulence
type="fractalNoise"
baseFrequency="0.02"
numOctaves="1"
result="noise"
/>
<feDisplacementMap in="SourceGraphic" in2="noise" scale="0.5" />
<feGaussianBlur stdDeviation="0.2" />
</filter>
</defs>
</svg>
);
export {
SketchAccordion,
SketchAccordionItem,
SketchAccordionTrigger,
SketchAccordionContent,
PencilFilter,
};
Update the import paths to match your project setup.
import {
SketchAccordion,
SketchAccordionContent,
SketchAccordionItem,
SketchAccordionTrigger,
PencilFilter,
} from "@/components/ui/sketch-accordion";
Update your styles.
The component uses Tailwind CSS for styling. Make sure your tailwind.config.js
includes the following:
module.exports = {
theme: {
extend: {
keyframes: {
"accordion-down": {
from: { height: 0 },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: 0 },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
},
},
};
Examples
Basic Usage
<SketchAccordion type="single" collapsible>
<SketchAccordionItem value="item-1">
<SketchAccordionTrigger>Section Title</SketchAccordionTrigger>
<SketchAccordionContent>Section content goes here</SketchAccordionContent>
</SketchAccordionItem>
</SketchAccordion>
Multiple Sections
<SketchAccordion type="multiple">
<SketchAccordionItem value="item-1">
<SketchAccordionTrigger>First Section</SketchAccordionTrigger>
<SketchAccordionContent>First section content</SketchAccordionContent>
</SketchAccordionItem>
<SketchAccordionItem value="item-2">
<SketchAccordionTrigger>Second Section</SketchAccordionTrigger>
<SketchAccordionContent>Second section content</SketchAccordionContent>
</SketchAccordionItem>
</SketchAccordion>
Custom Styling
<SketchAccordion type="single" collapsible>
<SketchAccordionItem
value="item-1"
className="border-blue-200 dark:border-blue-800"
>
<SketchAccordionTrigger className="hover:bg-blue-50 dark:hover:bg-blue-900">
Custom Styled Section
</SketchAccordionTrigger>
<SketchAccordionContent>Content with custom styling</SketchAccordionContent>
</SketchAccordionItem>
</SketchAccordion>
Props
Sketch Accordion
Prop name | Type | Default | Description |
---|---|---|---|
type | "single" | "multiple" | "single" | Determines whether one or multiple items can be opened |
collapsible | boolean | false | When type is "single", allows closing content by clicking |
value | string | - | The controlled value of the opened item |
defaultValue | string | - | The default value of the opened item |
className | string | - | Additional CSS classes |
Sketch Accordion Item
Prop name | Type | Default | Description |
---|---|---|---|
value | string | - | A unique value for the accordion item |
disabled | boolean | false | When true, prevents user interaction with the item |
className | string | - | Additional CSS classes |
Sketch Accordion Trigger
Prop name | Type | Default | Description |
---|---|---|---|
children | React.ReactNode | - | Content to display in trigger |
className | string | - | Additional CSS classes |
Sketch Accordion Content
Prop name | Type | Default | Description |
---|---|---|---|
children | React.ReactNode | - | Content to display when open |
className | string | - | Additional CSS classes |