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

@winzenburg/react

v2.0.0

Published

React components for the design system

Readme

@winzenburg/react

Production-ready React components built with accessibility and performance in mind

NPM Version Bundle Size TypeScript

A comprehensive library of accessible, performant React components built on top of our design token system. Every component is designed to meet WCAG 2.2 AA standards and provides excellent developer experience with TypeScript support.

Installation

# Install both packages (tokens required for styling)
npm install @winzenburg/react @winzenburg/tokens

# Or with yarn
yarn add @winzenburg/react @winzenburg/tokens

Basic Setup

// 1. Import CSS tokens in your app entry point (required)
import '@winzenburg/tokens/css'

// 2. Import and use components
import { Button, Stack, Typography } from '@winzenburg/react'

function App() {
  return (
    <Stack gap="4" align="center">
      <Typography variant="h1">Welcome to our Design System</Typography>
      <Button variant="solid" size="lg" onClick={() => alert('Hello!')}>
        Get Started
      </Button>
    </Stack>
  )
}

Import Styles

The component styles are automatically included, but you need the design tokens CSS:

Option 1: CSS Import (Recommended)

/* In your main CSS file */
@import '@winzenburg/tokens/css';

Option 2: JavaScript Import

// In your app entry point (index.js, App.js, etc.)
import '@winzenburg/tokens/css'

Option 3: Individual Component Styles

// Import specific component styles if needed
import '@winzenburg/react/styles'

Components

Form Elements

import { 
  Button, 
  Input, 
  Textarea, 
  Select, 
  Checkbox, 
  Radio,
  Switch
} from '@winzenburg/react'

function ContactForm() {
  return (
    <form>
      <Input 
        label="Full Name" 
        placeholder="Enter your name"
        required 
      />
      
      <Input 
        type="email" 
        label="Email Address" 
        placeholder="Enter your email"
        required 
      />
      
      <Textarea 
        label="Message" 
        placeholder="Tell us about your project"
        rows={4}
      />
      
      <Checkbox label="Subscribe to updates" />
      
      <Button type="submit" variant="solid" size="lg">
        Send Message
      </Button>
    </form>
  )
}

Layout Components

import { Stack, Grid, Card, Container } from '@winzenburg/react'

function ProductGrid() {
  return (
    <Container maxWidth="lg">
      <Grid columns={{ base: 1, md: 2, lg: 3 }} gap="6">
        {products.map(product => (
          <Card key={product.id} padding="6">
            <Stack gap="3">
              <Typography variant="h3">{product.name}</Typography>
              <Typography variant="body" color="muted">
                {product.description}
              </Typography>
              <Button variant="outline" size="sm">
                Learn More
              </Button>
            </Stack>
          </Card>
        ))}
      </Grid>
    </Container>
  )
}

Navigation Components

import { Tabs, Breadcrumb, Link } from '@winzenburg/react'

function Navigation() {
  return (
    <div>
      <Breadcrumb>
        <Link href="/">Home</Link>
        <Link href="/products">Products</Link>
        <span>Detail</span>
      </Breadcrumb>
      
      <Tabs defaultValue="overview">
        <Tabs.List>
          <Tabs.Trigger value="overview">Overview</Tabs.Trigger>
          <Tabs.Trigger value="features">Features</Tabs.Trigger>
          <Tabs.Trigger value="specs">Specifications</Tabs.Trigger>
        </Tabs.List>
        
        <Tabs.Content value="overview">
          <Typography>Product overview content...</Typography>
        </Tabs.Content>
        
        <Tabs.Content value="features">
          <Typography>Product features content...</Typography>
        </Tabs.Content>
        
        <Tabs.Content value="specs">
          <Typography>Product specifications...</Typography>
        </Tabs.Content>
      </Tabs>
    </div>
  )
}

Import Patterns

Barrel Imports (Convenience)

// Import multiple components at once
import { Button, Input, Stack, Typography } from '@winzenburg/react'

Individual Imports (Optimal Bundle Size)

// Import individual components for better tree-shaking
import { Button } from '@winzenburg/react/components/Button'
import { Input } from '@winzenburg/react/components/Input'
import { Stack } from '@winzenburg/react/components/Stack'

Utility Imports

// Import utility functions
import { cn } from '@winzenburg/react/utils'

// Usage
<div className={cn('base-class', { 'conditional-class': condition })} />

TypeScript Support

Full TypeScript support with comprehensive type definitions:

import { Button, ButtonProps } from '@winzenburg/react'

// Component props are fully typed
function CustomButton(props: ButtonProps) {
  return <Button {...props} />
}

// Ref forwarding support
function MyComponent() {
  const buttonRef = useRef<HTMLButtonElement>(null)
  
  return (
    <Button 
      ref={buttonRef}
      variant="solid"
      size="lg"
      onClick={() => console.log('Clicked!')}
    >
      Click me
    </Button>
  )
}

Styling and Customization

Using Design Tokens

Components automatically use design tokens, but you can customize with CSS variables:

.custom-button {
  /* Override component-specific tokens */
  --button-bg: var(--ds-color-purple-500);
  --button-fg: var(--ds-color-white);
  
  /* Or use any design system token */
  border-radius: var(--ds-radius-lg);
  box-shadow: var(--ds-shadow-xl);
}

Custom Styling with className

import { Button } from '@winzenburg/react'
import styles from './MyComponent.module.css'

function MyComponent() {
  return (
    <Button 
      className={styles.customButton}
      variant="outline"
    >
      Custom Styled Button
    </Button>
  )
}

Style Props

Some components support style props for common customizations:

<Stack 
  gap="4" 
  padding="6"
  borderRadius="md"
  backgroundColor="gray.50"
>
  <Typography>Styled with props</Typography>
</Stack>

Accessibility Features

All components are built with accessibility in mind:

Keyboard Navigation

  • Full keyboard support for all interactive elements
  • Proper focus management and visual indicators
  • Arrow key navigation for complex components

Screen Reader Support

  • Semantic HTML elements
  • Proper ARIA labels, roles, and properties
  • Live region announcements for dynamic content

High Contrast Support

  • Works with Windows High Contrast mode
  • Respects prefers-contrast media query
  • Sufficient color contrast ratios (4.5:1 minimum)

Example: Accessible Form

import { Input, Button, Stack } from '@winzenburg/react'

function AccessibleForm() {
  return (
    <form role="form" aria-label="Contact form">
      <Stack gap="4">
        <Input
          id="name"
          label="Full Name"
          placeholder="Enter your full name"
          required
          aria-describedby="name-help"
        />
        <div id="name-help">We'll use this to personalize your experience</div>
        
        <Input
          type="email"
          id="email"
          label="Email Address"
          placeholder="Enter your email"
          required
          aria-invalid={emailError ? 'true' : 'false'}
          aria-describedby={emailError ? 'email-error' : undefined}
        />
        {emailError && (
          <div id="email-error" role="alert">
            Please enter a valid email address
          </div>
        )}
        
        <Button type="submit" variant="solid">
          Submit Form
        </Button>
      </Stack>
    </form>
  )
}

Performance

Bundle Size

  • Full library: ~15KB gzipped
  • Individual components: 1-5KB each when tree-shaken
  • CSS: Included automatically, ~3KB additional

Tree Shaking

Import only what you need for optimal bundle sizes:

// ✅ Good - Only imports Button component
import { Button } from '@winzenburg/react/components/Button'

// ❌ Imports entire library (still tree-shakeable but less optimal)
import { Button } from '@winzenburg/react'

Server-Side Rendering (SSR)

All components support SSR with frameworks like Next.js, Remix, and Gatsby:

// Works out of the box with SSR
import { Button } from '@winzenburg/react'

export default function Page() {
  return <Button>Server-rendered button</Button>
}

Theme Support

Built-in Theme Utilities

The library includes built-in utilities for theme management that handle SSR compatibility and provide a clean API:

import { setTheme, setThemeOnly, setProductOnly, getCurrentTheme, resetTheme } from '@winzenburg/react'

// Set both theme and product preset
setTheme('dark', 'trust')

// Set only theme (preserves existing product)
setThemeOnly('light')

// Set only product preset (preserves existing theme)
setProductOnly('momentum')

// Get current theme settings
const { theme, product } = getCurrentTheme()

// Reset to defaults
resetTheme()

Theme Toggle Component Example

import { useState, useEffect } from 'react'
import { Button } from '@winzenburg/react'
import { setTheme, getCurrentTheme } from '@winzenburg/react'

function ThemeToggle() {
  const [currentTheme, setCurrentTheme] = useState('light')
  const [currentProduct, setCurrentProduct] = useState('trust')
  
  // Initialize from current DOM state
  useEffect(() => {
    const current = getCurrentTheme()
    if (current.theme) setCurrentTheme(current.theme)
    if (current.product) setCurrentProduct(current.product)
  }, [])
  
  const toggleTheme = () => {
    const newTheme = currentTheme === 'light' ? 'dark' : 'light'
    setTheme(newTheme, currentProduct)
    setCurrentTheme(newTheme)
  }
  
  return (
    <Button 
      variant="ghost" 
      onClick={toggleTheme}
      aria-label={`Switch to ${currentTheme === 'light' ? 'dark' : 'light'} theme`}
    >
      {currentTheme === 'light' ? 'Dark' : 'Light'} Mode
    </Button>
  )
}

App Layout Integration

// In your app root or layout component
import { useEffect, useState } from 'react'
import { setTheme, getCurrentTheme } from '@winzenburg/react'

function AppLayout({ children }) {
  const [isLoaded, setIsLoaded] = useState(false)
  
  useEffect(() => {
    // Initialize theme on app start
    const savedTheme = localStorage.getItem('theme') || 'light'
    const savedProduct = localStorage.getItem('product') || 'trust'
    
    setTheme(savedTheme, savedProduct)
    setIsLoaded(true)
  }, [])
  
  const handleThemeChange = (theme, product) => {
    setTheme(theme, product)
    localStorage.setItem('theme', theme)
    localStorage.setItem('product', product)
  }
  
  if (!isLoaded) {
    return <div>Loading...</div> // Prevent flash of unstyled content
  }
  
  return (
    <div className="app-layout">
      <header>
        <ThemeToggle onThemeChange={handleThemeChange} />
      </header>
      <main>{children}</main>
    </div>
  )
}

Product Presets

The design system supports multiple product emotional presets:

import { setProductOnly } from '@winzenburg/react'

// Available presets: 'trust', 'momentum', 'inspiration', 'calm', 'rhythm', 'care'
const presets = [
  { id: 'trust', name: 'Trust', description: 'Professional, stable, reliable' },
  { id: 'momentum', name: 'Momentum', description: 'Energetic, forward-moving' },
  { id: 'inspiration', name: 'Inspiration', description: 'Creative, imaginative' },
  { id: 'calm', name: 'Calm', description: 'Peaceful, soothing' },
  { id: 'rhythm', name: 'Rhythm', description: 'Systematic, efficient' },
  { id: 'care', name: 'Care', description: 'Professional, trustworthy' }
]

function PresetSelector() {
  return (
    <div>
      {presets.map(preset => (
        <Button
          key={preset.id}
          variant="outline"
          onClick={() => setProductOnly(preset.id)}
        >
          {preset.name}
        </Button>
      ))}
    </div>
  )
}

SSR-Safe Theme Management

The theme utilities automatically handle server-side rendering:

// ✅ Safe to call during SSR - will log warning but not crash
useEffect(() => {
  setTheme('dark', 'momentum')
}, [])

// ✅ Safe to call during SSR - returns null values
const { theme, product } = getCurrentTheme()

Custom Brand Themes

/* Define custom theme */
[data-theme="brand"] {
  --ds-color-primary-500: #your-brand-color;
  --ds-color-primary-600: #your-darker-shade;
}
<div data-theme="brand">
  <Button variant="solid">Branded Button</Button>
</div>

Component API Patterns

Consistent Prop Patterns

All components follow consistent patterns:

interface ComponentProps {
  // Standard HTML props
  className?: string
  style?: React.CSSProperties
  children?: React.ReactNode
  
  // Component-specific variants
  variant?: 'primary' | 'secondary' | 'outline' | 'ghost'
  size?: 'sm' | 'md' | 'lg'
  
  // State props (when applicable)
  disabled?: boolean
  loading?: boolean
  
  // Controlled/uncontrolled patterns
  value?: string
  defaultValue?: string
  onChange?: (value: string) => void
  
  // Event handlers
  onPress?: () => void
  onFocus?: () => void
  onBlur?: () => void
}

Ref Forwarding

All components support ref forwarding:

const buttonRef = useRef<HTMLButtonElement>(null)

<Button ref={buttonRef}>Click me</Button>

Polymorphic Components

Some components support the as prop:

// Render as different HTML elements
<Button as="a" href="/link">Link Button</Button>
<Typography as="h1">Heading</Typography>
<Stack as="section">Section Content</Stack>

Testing

Testing Library Integration

Components work seamlessly with React Testing Library:

import { render, screen, fireEvent } from '@testing-library/react'
import { Button } from '@winzenburg/react'

test('button click handler', () => {
  const handleClick = jest.fn()
  
  render(<Button onClick={handleClick}>Click me</Button>)
  
  fireEvent.click(screen.getByRole('button', { name: /click me/i }))
  
  expect(handleClick).toHaveBeenCalledTimes(1)
})

Accessibility Testing

import { axe, toHaveNoViolations } from 'jest-axe'

expect.extend(toHaveNoViolations)

test('should not have accessibility violations', async () => {
  const { container } = render(<Button>Accessible button</Button>)
  const results = await axe(container)
  expect(results).toHaveNoViolations()
})

Browser Support

| Browser | Version | |---------|---------| | Chrome | 88+ | | Firefox | 85+ | | Safari | 14+ | | Edge | 88+ |

Migration Guide

From v0.x to v1.x

Breaking changes and migration steps:

  1. Import paths changed:

    // Before
    import Button from '@winzenburg/react/Button'
       
    // After
    import { Button } from '@winzenburg/react'
  2. Prop renames:

    // Before
    <Button type="primary" />
       
    // After
    <Button variant="solid" />
  3. CSS import required:

    // Add this to your app
    import '@winzenburg/tokens/css'

See CHANGELOG.md for complete migration guide.

Contributing

See the main Contributing Guide for development setup and contribution guidelines.

Examples Repository

Check out our examples repository for:

  • Next.js integration
  • Remix integration
  • Storybook setup
  • Custom theming examples
  • Advanced component compositions

Support

License

MIT © Your Organization