npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@papernote/ui

v2.1.2

Published

A modern React component library with a paper notebook aesthetic - minimal, professional, and expressive

Downloads

1,197

Readme

@papernote/ui

npm version License: MIT TypeScript Storybook

A modern React component library with a paper notebook aesthetic - minimal, professional, and expressive. Built with TypeScript, Tailwind CSS, and designed for production use.

📖 Documentation

📚 View Full Documentation →

Quick Links: 🎨 Storybook📦 npm

✨ Features

  • 🎨 Paper Notebook Aesthetic - Subtle grain textures, muted warm colors, inspired by quality paper notebooks
  • 115+ Components - Comprehensive set of production-ready React components
  • 📚 45+ Storybook Stories - Extensive documentation with 500+ interactive examples
  • 🎯 TypeScript First - Full TypeScript support with comprehensive type definitions
  • 🎨 Tailwind CSS v3 - Built on Tailwind with custom design tokens
  • Accessible - WCAG AA compliant with ARIA attributes and keyboard navigation
  • 🚀 Tree-shakeable - Import only what you need
  • 📱 Responsive - Mobile-first design with responsive utilities
  • 🔧 Virtual Scrolling - High-performance rendering for large datasets (DataTable)
  • 🎯 forwardRef Support - All form components support ref forwarding

📦 Installation

npm install @papernote/ui
# or
yarn add @papernote/ui
# or
pnpm add @papernote/ui

Peer Dependencies

npm install react react-dom react-router-dom lucide-react tailwindcss

🚀 Quick Start

1. Import Styles

In your main entry file (e.g., src/main.tsx):

import '@papernote/ui/styles';

2. Configure Tailwind

In your tailwind.config.js:

import notebookConfig from '@papernote/ui/tailwind-config';

export default {
  ...notebookConfig,
  content: [
    './src/**/*.{js,ts,jsx,tsx}',
    './node_modules/@papernote/ui/src/**/*.{js,ts,jsx,tsx}',
  ],
};

3. Use Components

import { Button, Card, CardHeader, CardTitle, CardContent } from '@papernote/ui';

function App() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Welcome to @papernote/ui</CardTitle>
      </CardHeader>
      <CardContent>
        <p>A beautiful component library with paper notebook aesthetic</p>
        <Button variant="primary">Get Started</Button>
      </CardContent>
    </Card>
  );
}

🧩 Component Categories

Form Components (15+)

  • Button - Primary, secondary, ghost, danger, outline variants with loading states
  • Input - Text input with prefix/suffix icons, clearable, validation states
  • Select - Searchable dropdown with clearable option
  • MultiSelect - Multiple selection dropdown
  • Textarea - Auto-expanding text area with resize control
  • Checkbox - Checkbox with icon support
  • Radio - Radio buttons with icon support
  • Switch - Toggle switch with loading state
  • Slider - Range input with value display
  • DatePicker - Calendar date picker with events and range mode
  • TimePicker - Time selection input
  • ColorPicker - Color selector with presets
  • FileUpload - Drag-and-drop file upload
  • PasswordInput - Password field with show/hide toggle
  • NumberInput - Numeric input with step controls

Layout Components (12+)

  • Card - Container with Header, Title, Content, Footer sections
  • Stack - Vertical/horizontal flex layout
  • Grid - Responsive grid system with GridItem
  • Box - Generic container with spacing utilities
  • Text - Typography component with size variants
  • Page - Notebook-style page background with ruled lines
  • PageLayout - Standard page layout with title and description
  • Layout - Complete app layout with sidebar and gutter navigation
  • AppLayout - Layout with expandable toolbar and status bar
  • Dashboard - Dashboard container with DashboardHeader and DashboardContent
  • TwoColumnContent - 1/3 sidebar + 2/3 main content layout
  • Separator - Horizontal/vertical divider

Navigation Components (10+)

  • Sidebar - Collapsible navigation sidebar with nested items
  • Breadcrumbs - Path navigation with custom separators
  • Pagination - Page navigation with size options
  • Tabs - Tab navigation (underline and pill variants, vertical/horizontal)
  • StepIndicator - Progress stepper
  • TreeView - Hierarchical tree navigation with expand/collapse
  • CommandPalette - Keyboard-driven command launcher (Cmd+K style)
  • PageNavigation - Scrollspy navigation dots for page sections
  • Dropdown - Action menu with icons and dividers
  • Menu - Context menu component

Data Display Components (10+)

  • DataTable - Feature-rich table with sorting, filtering, selection, row actions, expansion, virtual scrolling
  • Table - Basic table component
  • Badge - Status indicators with dot variant
  • StatusBadge - Status badges with color variants
  • Avatar - User avatars with fallback initials
  • Timeline - Vertical/horizontal event timeline
  • KanbanBoard - Drag-and-drop kanban board
  • Calendar - Full calendar with event markers
  • CurrencyDisplay - Formatted currency display
  • DateDisplay - Formatted date display
  • StatCard - Statistics card with trends

Feedback Components (8+)

  • Toast - Notification system (success, error, warning, info) with position control
  • Alert - Notification banners with action buttons
  • Modal - Dialog with multiple sizes and animation variants
  • Drawer - Side-sliding panel (left, right, top, bottom)
  • Tooltip - Hover tooltips with positioning
  • EmptyState - No data/empty states
  • Loading - Spinners, dots, pulse loaders
  • Skeleton - Loading placeholders (SkeletonCard, SkeletonTable)
  • LoadingOverlay - Full-screen loading overlay
  • ConfirmDialog - Confirmation dialogs

Advanced Components (15+)

  • Accordion - Collapsible panels with custom icons
  • Transfer - Dual-list item transfer with search
  • Carousel - Image/content carousel with auto-play
  • Stepper - Multi-step wizard (horizontal/vertical)
  • Rating - Star rating input with half-star support
  • Progress - Linear and circular progress indicators
  • Popover - Rich content popovers with positioning
  • ButtonGroup - Toggle button groups (single/multiple selection)
  • Autocomplete - Auto-suggest input
  • Combobox - Searchable select with custom options
  • DateRangePicker - Date range selection
  • RichTextEditor - WYSIWYG editor
  • MarkdownEditor - Markdown editing
  • InfiniteScroll - Infinite scroll loading
  • ContextMenu - Right-click context menus

Utility Components (5+)

  • Show/Hide - Responsive visibility utilities
  • ErrorBoundary - Error boundary wrapper
  • ThemeToggle - Dark/light mode toggle
  • QueryTransparency - SQL query explanation
  • NotificationIndicator - Badge notification dots

🎨 Design System

Color Palette

The library uses a muted, warm color palette inspired by paper and ink:

{
  paper: {
    50: '#fafaf9',   // Off-white background
    100: '#f5f5f4',  // Light gray
    200: '#e7e5e4',  // Border gray
    300: '#d6d3d1',  // Subtle border
  },
  ink: {
    600: '#57534e',  // Body text
    700: '#44403c',  // Headings
    900: '#1c1917',  // High contrast
  },
  accent: '#8b8878',    // Warm gray accents
  primary: '#64748b',   // Slate blue
  success: '#10b981',   // Muted emerald
  warning: '#f59e0b',   // Soft amber
  error: '#ef4444',     // Muted red
}

Typography

  • Font Family: System font stack (ui-sans-serif, system-ui, sans-serif)
  • Font Sizes: 12px (xs) to 48px (4xl)
  • Line Heights: 1.5 (body), 1.2 (headings)
  • Font Weights: 400 (normal), 500 (medium), 600 (semibold), 700 (bold)

Shadows & Effects

  • Subtle paper-like box shadows
  • SVG noise texture for paper grain
  • Smooth transitions (150ms-300ms)
  • Border radius: 0.375rem (6px) standard

📚 Component Examples

Button with Loading State

import { Button } from '@papernote/ui';
import { Save } from 'lucide-react';

<Button 
  variant="primary" 
  size="md" 
  loading={isSaving}
  icon={<Save />}
  onClick={handleSave}
>
  Save Changes
</Button>

Toast Notifications

import { addSuccessMessage, addErrorMessage, ToastContainer } from '@papernote/ui';

function App() {
  const handleSuccess = () => {
    addSuccessMessage('Changes saved successfully!');
  };

  const handleError = () => {
    addErrorMessage('Failed to save changes', 'Please try again');
  };

  return (
    <>
      <Button onClick={handleSuccess}>Show Success</Button>
      <Button onClick={handleError}>Show Error</Button>
      <ToastContainer position="top-right" />
    </>
  );
}

DataTable with Advanced Features

import { DataTable } from '@papernote/ui';
import { Edit, Trash } from 'lucide-react';

const columns = [
  { key: 'name', header: 'Name', sortable: true, filterable: true },
  { key: 'email', header: 'Email', sortable: true },
  { 
    key: 'status', 
    header: 'Status',
    render: (row) => <Badge variant={row.status === 'active' ? 'success' : 'default'}>{row.status}</Badge>
  },
];

const actions = [
  { 
    label: 'Edit', 
    icon: <Edit className="h-4 w-4" />, 
    onClick: (row) => handleEdit(row) 
  },
  { 
    label: 'Delete', 
    icon: <Trash className="h-4 w-4" />, 
    onClick: (row) => handleDelete(row), 
    variant: 'danger' as const 
  },
];

<DataTable
  data={users}
  columns={columns}
  actions={actions}
  loading={loading}
  selectable
  onRowSelect={(selectedRows) => console.log(selectedRows)}
  expandable
  renderExpandedRow={(row) => <UserDetails user={row} />}
  virtualized // Enable for 10,000+ rows
  virtualHeight="600px"
/>

Form with Validation

import { Input, Textarea, Select, Button, Card } from '@papernote/ui';
import { useState } from 'react';

function ContactForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    category: '',
    message: ''
  });

  return (
    <Card>
      <CardHeader>
        <CardTitle>Contact Us</CardTitle>
      </CardHeader>
      <CardContent>
        <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
          <Input
            label="Name"
            value={formData.name}
            onChange={(e) => setFormData({ ...formData, name: e.target.value })}
            required
          />
          <Input
            label="Email"
            type="email"
            value={formData.email}
            onChange={(e) => setFormData({ ...formData, email: e.target.value })}
            required
          />
          <Select
            label="Category"
            options={[
              { value: 'general', label: 'General Inquiry' },
              { value: 'support', label: 'Support' },
              { value: 'feedback', label: 'Feedback' }
            ]}
            value={formData.category}
            onChange={setFormData({ ...formData, category: value })}
          />
          <Textarea
            label="Message"
            value={formData.message}
            onChange={(e) => setFormData({ ...formData, message: e.target.value })}
            rows={4}
          />
          <Button variant="primary" type="submit">
            Send Message
          </Button>
        </div>
      </CardContent>
    </Card>
  );
}

Layout with Sidebar

import { Layout, Sidebar, Page, StatusBar } from '@papernote/ui';
import { Home, Users, Settings } from 'lucide-react';

const menuItems = [
  { id: 'home', label: 'Home', icon: <Home />, href: '/' },
  { id: 'users', label: 'Users', icon: <Users />, href: '/users' },
  { id: 'settings', label: 'Settings', icon: <Settings />, href: '/settings' },
];

function App() {
  return (
    <Layout
      sidebar={<Sidebar items={menuItems} />}
      statusBar={<StatusBar />}
    >
      <Page>
        {/* Your page content */}
      </Page>
    </Layout>
  );
}

🛠️ Development

# Install dependencies
npm install

# Build library
npm run build

# Build Storybook
npm run build-storybook

# Type check
npm run typecheck

# Lint
npm run lint

📖 Documentation

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

MIT License - Copyright (c) 2025 kwhittenberger

See LICENSE for full details.

🙏 Credits

Inspired by the minimal, professional aesthetic of quality paper notebooks and Claude's interface design.

🔗 Links