@srekaravarshan.dev/feather
v0.1.0
Published
Tree-shakable React component library with vanilla-extract
Downloads
75
Maintainers
Readme
@sparrowengg/feather
A tree-shakable React component library built with vanilla-extract for optimal bundle sizes.
Features
- 🌲 Tree-shakable - Import only what you need
- 📦 Tiny bundles - Each component is separately compiled
- 🎨 vanilla-extract - Zero-runtime CSS with static extraction
- 🔷 TypeScript - Full type safety
- ⚡ Fast - Build-time CSS with no runtime overhead
- 🧪 Well tested - Comprehensive test coverage
Installation
npm install @sparrowengg/feather
# or
yarn add @sparrowengg/feather
# or
pnpm add @sparrowengg/featherPeer Dependencies
Make sure you have React 18+ installed:
npm install react react-domUsage
Setup (Required)
All Feather components require the FeatherThemeProvider wrapper. This applies the theme CSS variables needed by all components:
import { FeatherThemeProvider } from '@sparrowengg/feather/theme';
import { Button } from '@sparrowengg/feather/button';
function App() {
return (
<FeatherThemeProvider>
<Button variant="solid" size="md">Click me</Button>
</FeatherThemeProvider>
);
}Importing Components
Import components individually for optimal tree-shaking:
import { Button } from '@sparrowengg/feather/button';
import { Toast } from '@sparrowengg/feather/toast';
import { Tooltip } from '@sparrowengg/feather/tooltip';Theme Customization
Feather uses vanilla-extract for styling, which means you can create custom themes at build time using createTheme:
Step 1: Create your custom theme (in your app, e.g., app/theme.css.ts):
import { createTheme } from '@vanilla-extract/css';
import { vars } from '@sparrowengg/feather/theme';
export const myAppTheme = createTheme(vars, {
font: {
body: 'Inter, system-ui, sans-serif',
heading: 'Inter, system-ui, sans-serif',
theme: 'Inter, system-ui, sans-serif',
},
colors: {
primary: {
500: '#0066cc',
600: '#0052a3',
// ... customize other shades as needed
},
},
// Override any other tokens as needed
});Step 2: Apply your theme using FeatherThemeProvider:
import { FeatherThemeProvider } from '@sparrowengg/feather/theme';
import { myAppTheme } from './theme.css';
function App() {
return (
<FeatherThemeProvider themeClass={myAppTheme}>
<YourApp />
</FeatherThemeProvider>
);
}Benefits of this approach:
- ✅ 100% static CSS - No runtime overhead
- ✅ Type-safe - Full TypeScript support for all theme tokens
- ✅ Tree-shakable - Only the styles you use are included
- ✅ Scoped - Multiple themes can coexist in the same app
- ✅ Optimized bundles - Theme CSS is loaded once, not duplicated per component (~35KB savings)
Components
Button
A versatile button component with multiple variants and sizes.
import { Button, IconButton } from '@sparrowengg/feather/button';
import '@sparrowengg/feather/button.css';
// Basic button
<Button>Click me</Button>
// With variants
<Button variant="solid">Solid</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="outline">Outline</Button>
// With sizes
<Button size="xs">Extra Small</Button>
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
// With colors
<Button color="primary">Primary</Button>
<Button color="default">Default</Button>
// Icon button
<IconButton icon={<Icon />} aria-label="Action" />
<IconButton icon={<Icon />} shape="round" aria-label="Round" />
// With states
<Button disabled>Disabled</Button>
<Button loading>Loading</Button>Props:
variant:'solid' | 'ghost' | 'outline'(default:'solid')size:'xxs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'(default:'sm')color:'default' | 'primary' | 'secondary' | 'bright' | 'light' | 'error' | 'none'(default:'primary')disabled:booleanloading:booleanleftIcon:ReactElementrightIcon:ReactElementicon:ReactElement(for icon-only buttons)
Popover
A popover component with smart positioning.
import { Popover, PopoverTrigger, PopoverContent } from '@sparrowengg/feather/popover';
import '@sparrowengg/feather/popover.css';
<Popover>
<PopoverTrigger>
<button>Open Popover</button>
</PopoverTrigger>
<PopoverContent className="your-styles">
<div>Popover content goes here</div>
</PopoverContent>
</Popover>
// With custom trigger
<Popover>
<PopoverTrigger asChild>
<Button>Custom Trigger</Button>
</PopoverTrigger>
<PopoverContent>Content</PopoverContent>
</Popover>Features:
- Automatic positioning
- Click outside to close
- Portal rendering
- Scroll and resize aware
Toast
A toast notification system.
import { toast, ToastContainer } from '@sparrowengg/feather/toast';
import '@sparrowengg/feather/toast.css';
// Add ToastContainer to your app root
function App() {
return (
<>
<YourApp />
<ToastContainer />
</>
);
}
// Show toasts anywhere in your app
toast({ message: 'Success!', variant: 'success' });
toast({ message: 'Error occurred', variant: 'error' });
toast({ message: 'Warning!', variant: 'warning' });
toast({ message: 'Info message', variant: 'info' });Features:
- Auto-dismiss after 5 seconds
- Multiple toasts support
- Portal rendering
- Variant-based styling
Tooltip
A tooltip component with smart positioning and animations.
import { Tooltip, TooltipProvider } from '@sparrowengg/feather/tooltip';
import '@sparrowengg/feather/tooltip.css';
// Wrap your app with TooltipProvider
function App() {
return (
<TooltipProvider>
<YourApp />
</TooltipProvider>
);
}
// Use tooltips
<Tooltip content="This is a tooltip">
<button>Hover me</button>
</Tooltip>
// With positioning
<Tooltip content="Top tooltip" side="top">
<button>Hover me</button>
</Tooltip>
<Tooltip content="Right tooltip" side="right" align="start">
<button>Hover me</button>
</Tooltip>
// With custom delay
<Tooltip content="Delayed tooltip" delayDuration={1000}>
<button>Hover me</button>
</Tooltip>
// Disabled tooltip
<Tooltip content="Won't show" disabled>
<button>Hover me</button>
</Tooltip>Props:
content:ReactNode- Tooltip contentside:'top' | 'bottom' | 'left' | 'right'(default:'top')align:'start' | 'center' | 'end'(default:'center')sideOffset:number(default:8)alignOffset:number(default:0)disabled:boolean(default:false)delayDuration:number- Override provider delay
TooltipProvider Props:
delayDuration:number(default:700) - Initial hover delayskipDelayDuration:number(default:300) - Time window to skip delay when switching tooltips
Bundle Size
Each component is optimized for minimal bundle size:
| Component | JS (gzipped) | CSS (gzipped) | |-----------|--------------|---------------| | Button | ~3-5 KB | ~1-2 KB | | Popover | ~2-3 KB | ~0.5 KB | | Toast | ~2-3 KB | ~1 KB | | Tooltip | ~4-5 KB | ~1-2 KB |
Tree-shaking works! Only import what you use:
// ✅ Good - Only Button code is bundled
import { Button } from '@sparrowengg/feather/button';
// ❌ Avoid - Would bundle everything (if barrel export existed)
// import { Button } from '@sparrowengg/feather';Development
# Install dependencies
pnpm install
# Build the package
pnpm build
# Run tests
pnpm test
# Run tests in watch mode
pnpm test:watch
# Generate coverage report
pnpm test:coverageCode Quality
# Full quality check (typecheck + lint + knip + test)
pnpm check
# Type check
pnpm tscheck
# Lint and format check
pnpm lint
# Lint and format fix
pnpm fix
# Check for unused code, styles, and dependencies
pnpm knip
# Full analysis (knip + typecheck)
pnpm analyzeLinting & Formatting
This package uses Biome for fast linting and formatting:
# Check code (lint + format)
pnpm lint
# Auto-fix issues
pnpm lint:fix
# Format code
pnpm format
# Check formatting only
pnpm format:checkProject Structure
packages/feather/
├── src/
│ ├── button/
│ │ ├── button.tsx
│ │ ├── button.css.ts # vanilla-extract styles
│ │ ├── icon-button.tsx
│ │ ├── icon-button.css.ts # vanilla-extract styles
│ │ ├── utils.ts
│ │ └── index.tsx
│ ├── popover/
│ ├── toast/
│ ├── tooltip/
│ └── theme/
│ ├── theme.css.ts # Design tokens
│ └── utils.ts
├── tests/
│ ├── button.test.tsx
│ ├── popover.test.tsx
│ ├── toast.test.tsx
│ └── tooltip.test.tsx
├── dist/ # Built files (JS + extracted CSS)
└── package.jsonContributing
Contributions are welcome! Please read our contributing guidelines before submitting a PR.
License
MIT © Sparrow Engineering
Support
For issues and feature requests, please use GitHub Issues.
