Install

doodle-ui is a React 18+ library. rough.js ships with the package. React stays a peer dependency.

CLI (shadcn-style installer)

Copy component source code directly into your project so you own the styling, hooks, and sketch parameters. The CLI detects your package manager from lockfiles (package-lock.json, pnpm-lock.yaml, yarn.lock, bun.lockb / bun.lock).

# Initialize project configuration & copy shared utilities
npx doodleui-react init

# Add components directly into your codebase
npx doodleui-react add button card badge dialog

# List components and check installation status
npx doodleui-react list

# Compare local modifications against upstream registry
npx doodleui-react diff button

Package (npm dependency)

npm install doodleui-react
Package name
Install doodleui-react. The name doodle-ui is blocked on npm by an unpublished 2023 stub.

Quickstart

Wrap the tree once. TooltipProvider is required for tooltips. ToastProvider is required for toasts. SketchSeedProvider is required for Shuffle. DoodleUIProvider is optional — animations default on, and you can pass `animate=` on a component or on the provider.

import {
  DoodleUIProvider,
  SketchSeedProvider,
  TooltipProvider,
  Button,
  useSketchSeed,
} from "doodleui-react";

function Shuffle() {
  const { shuffle } = useSketchSeed();
  return <Button onClick={shuffle}>Shuffle</Button>;
}

export function App() {
  return (
    <DoodleUIProvider>
      <SketchSeedProvider>
        <TooltipProvider>
          <Shuffle />
          <Button variant="primary">Hello</Button>
        </TooltipProvider>
      </SketchSeedProvider>
    </DoodleUIProvider>
  );
}

Global theming: import doodleui-react/styles.css and override --doodle-ui-* variables. See Theming or the theme generator.

Lock a sketch

Pass seed={123} to freeze the wobble for visual tests. Omit it to follow the provider seed, which Shuffle increments.

SSR / Next.js

doodleui-react is SSR-safe with the Next.js App Router and Pages Router. Uncontrolled sketch seeds use a fixed default on the server and during the first client hydration pass, then pick a random seed after mount. That keeps React hydration quiet — you will not see mismatch warnings from rough.js wobble.

Because of that, the hand-drawn "wobble" for components without an explicit seed may settle only after the page is interactive. Pass seed={123} or wrap with <SketchSeedProvider initialSeed={123}> when you need a stable sketch on first paint (screenshots, Chromatic, marketing pages).

Shuffle via useSketchSeed() is user-triggered after mount and is unaffected. Import components from a Client Component ('use client') or from a Server Component that renders them as children — every public component already ships with the client directive.