sketchy-ui
v0.1.0
Published
A lightweight React component that wraps your content with a hand-drawn sketchy SVG border
Maintainers
Readme
sketchy-ui
A lightweight React component that wraps your content with a hand-drawn SVG border. Perfect for adding a sketchy, playful aesthetic to your UI elements.
Features
- 🎨 Randomly generated hand-drawn SVG borders
- 🎯 Lightweight with zero dependencies (except React)
- ⚡️ High performance - SVG generated once on mount
- 🎭 Smooth hover fill effects with CSS
- 🔧 Fully customizable (colors, stroke width, seed)
- 📦 TypeScript support included
- 🌲 Tree-shakeable ESM/CJS builds
- ♿️ Fully accessible - preserves interactivity and screen reader compatibility
Installation
npm install sketchy-uior
yarn add sketchy-uiUsage
import { Sketch } from 'sketchy-ui';
function App() {
return (
<Sketch
color="#333"
strokeWidth={2}
roughness="medium"
hoverFillColor="rgba(255, 200, 0, 0.1)"
>
<p>Your content here</p>
</Sketch>
);
}API
Props
| Prop | Type | Default | Description |
| ---------------- | ------------------------------- | --------------- | ------------------------------------------------------------------ |
| children | ReactNode | required | Content to wrap with hand-drawn border |
| color | string | '#000000' | Color of the sketch border |
| strokeWidth | number | 2 | Width of the border stroke |
| roughness | 'light' \| 'medium' \| 'hard' | 'medium' | Roughness level: light (subtle), medium (moderate), hard (sketchy) |
| hoverFillColor | string | 'transparent' | Fill color when hovering |
| seed | number | undefined | Seed for random generation (use same seed for consistent border) |
| className | string | undefined | Additional CSS class name |
| style | React.CSSProperties | undefined | Additional inline styles |
Examples
Basic Usage
<Sketch>
<button>Click me!</button>
</Sketch>With Hover Effect
<Sketch color="#ff6b6b" hoverFillColor="rgba(255, 107, 107, 0.1)">
<div>Hover over me!</div>
</Sketch>Different Roughness Levels
{
/* Light: subtle wobble, clean look */
}
<Sketch roughness="light" color="#333">
<p>Light sketchy border</p>
</Sketch>;
{
/* Medium: moderate wobble (default) */
}
<Sketch roughness="medium" color="#333">
<p>Medium sketchy border</p>
</Sketch>;
{
/* Hard: very sketchy appearance */
}
<Sketch roughness="hard" color="#333">
<p>Hard sketchy border</p>
</Sketch>;Consistent Border (Using Seed)
<Sketch seed={12345} roughness="medium">
<p>This border will always look the same</p>
</Sketch>SketchProvider
Use SketchProvider to set default sketch configuration for multiple components:
import { SketchProvider, useSketch, Sketch } from 'sketchy-ui';
function MyCard() {
const sketchConfig = useSketch();
return (
<Sketch {...sketchConfig}>
<div>This uses the provider's configuration</div>
</Sketch>
);
}
function App() {
return (
<SketchProvider roughness="medium" color="#333" strokeWidth={2}>
<MyCard />
<MyCard />
{/* All cards will use the same sketch config */}
</SketchProvider>
);
}useSketch Hook
The useSketch() hook returns the current sketch configuration from the nearest SketchProvider:
const sketchConfig = useSketch();
// Returns: { roughness, color, strokeWidth, hoverFillColor, enabled }Accessibility
The Sketch component is designed to be fully accessible and preserve all interactivity:
- ✅ Click-through: SVG overlay uses
pointerEvents: 'none'so all clicks, touches, and interactions pass through to wrapped elements - ✅ Keyboard navigation: Focus states and keyboard events work normally on wrapped elements
- ✅ Screen readers: SVG is marked with
aria-hidden="true"since it's purely decorative - ✅ Form controls: Buttons, inputs, and other interactive elements maintain full functionality
- ✅ Z-index management: Content is properly layered to ensure visibility and interactivity
Example with fully functional button:
<Sketch color="#333" roughness="medium">
<button onClick={handleClick} aria-label="Submit form">
Submit
</button>
</Sketch>;
{
/* Button remains fully clickable, keyboard accessible, and screen reader compatible */
}How It Works
The Sketch component uses multi-stroke rendering (inspired by Excalidraw) to create an authentic hand-drawn appearance:
- Multiple overlapping paths: Each component renders 2-3 slightly different paths
- Layered opacity: Strokes are layered with varying opacities for depth
- Per-level configuration: Each roughness level has tuned settings for strokes, offsets, and point density
- Control point randomness: Higher roughness levels have more organic variation in curve control points
- Lightweight & fast: SVG generation happens once on mount, with no runtime performance impact
Development
# Install dependencies
npm install
# Build the package
npm run build
# Watch mode for development
npm run dev
# Lint code
npm run lint
# Format code
npm run formatTesting Locally
The package includes a demo project in the examples/ directory. To test your component:
# Build the package
npm run build
# Navigate to the demo
cd examples/demo
# Install dependencies
npm install
# Run the demo
npm run devThe demo will be available at http://localhost:3000 and showcases various use cases of the component.
Publishing
# Build and publish to npm
npm run prepublishOnly
npm publish --access publicLicense
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
