React components with container queries and fluid scales. Dramatically fewer breakpoints.
Traditional responsive design is painful:
- Too many viewport breakpoints to manage
- Components respond to viewport, not their container
- Repetitive spacing and sizing logic
- Hard to maintain consistency
Wren solves these problems with:
- 📦 Container-based layouts - components adapt to their container size, not just viewport
- 📏 Fluid scales - spacing and typography scale smoothly using CSS clamp()
- 🎯 Minimal breakpoints - most layouts need zero custom breakpoints, a few need one
- ⚛️ React Native-style API - intuitive, declarative, type-safe
- 🌐 Progressive enhancement - uses container query units (cqi) in modern browsers, viewport units (vw) as fallback
npm install# Run documentation site
npm run dev
# Build library
npm run build:lib
# Build everything
npm run buildimport { Container, Box, Stack, Grid, Text } from '@wren/ui';
function App() {
return (
<Container maxWidth="xl" center>
{/* Responsive layout - switches from column to row automatically */}
<Stack direction="responsive" spacing="fluid-4">
{/* Sidebar takes 1/4 width with fluid padding */}
<Box flex={1} padding="fluid-5" background="#f5f5f5">
Sidebar
</Box>
{/* Main content takes 3/4 width */}
<Box flex={3} padding="fluid-5">
{/* Auto-fitting card grid - no breakpoints needed! */}
<Grid columns="auto-fit" minSize="250px" gap="fluid-4">
<Card />
<Card />
<Card />
</Grid>
</Box>
</Stack>
</Container>
);
}Wren provides sensible defaults, but every design system is different. Use WrenProvider to customize scales for your brand:
import { WrenProvider, Container, Box } from '@wren/ui';
function App() {
return (
<WrenProvider
config={{
scales: {
// Override existing scales
'fluid-4': { min: 1.25, max: 1.75 },
// Add intermediate values
'fluid-4.5': { min: 1.75, max: 2.25 },
// Brand-specific scales
'brand-hero': { min: 3, max: 8 },
'brand-compact': { min: 0.5, max: 0.625 },
},
scaleConfig: {
minViewport: 375, // Mobile-first
maxViewport: 1440, // Design comp max
unit: 'cqi' // or 'vw'
}
}}
>
<Container>
<Box padding="brand-hero">
Custom scale!
</Box>
</Container>
</WrenProvider>
);
}Benefits:
- 🎨 Match existing design systems - Override defaults to match Figma tokens or design language
- 🔧 Add intermediate values - Fill gaps in the default progression
- 🏢 Enterprise-ready - Custom scales enable gradual migration and team adoption
- ⚛️ Runtime theming - Change scales dynamically for theme switching
Establishes a container query context. All child components can respond to this container's size.
<Container maxWidth="lg" center>
{/* Your content */}
</Container>Props:
maxWidth:'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full' | stringcenter: boolean - center horizontally
The fundamental layout primitive. Provides spacing, flex layout, and sizing.
<Box
flex={1}
padding="fluid-5"
margin="fluid-3"
background="#fff"
borderRadius="8px"
>
Content
</Box>Props:
- Spacing:
padding,margin(with X/Y/Top/Bottom/Left/Right variants) - Flex:
flex,flexGrow,flexShrink,flexBasis,alignSelf - Size:
width,height,minWidth,maxWidth,minHeight,maxHeight - Positioning:
position,top,right,bottom,left,zIndex - Style:
background,borderRadius,border
Auto-layout stacking with consistent spacing.
<Stack direction="responsive" spacing="fluid-4" align="center">
<Box>Item 1</Box>
<Box>Item 2</Box>
<Box>Item 3</Box>
</Stack>Props:
direction:'row' | 'column' | 'responsive''responsive'switches from column to row based on container width
responsiveBreakpoint: number (default: 768) - container width breakpoint in pixels for responsive directionspacing: Fluid or fixed scale valuealign:'start' | 'center' | 'end' | 'stretch' | 'baseline'justify:'start' | 'center' | 'end' | 'space-between' | 'space-around' | 'space-evenly'wrap: boolean
Responsive grids without breakpoints. Items automatically wrap based on available space.
{/* Auto-fitting grid */}
<Grid columns="auto-fit" minSize="250px" gap="fluid-4">
<Card />
<Card />
<Card />
</Grid>
{/* Fixed columns with responsive fallback */}
<Grid columns={3} gap="fluid-3">
<Box>1</Box>
<Box>2</Box>
<Box>3</Box>
</Grid>Props:
columns:'auto-fit' | 'auto-fill' | number | stringminSize: string - minimum size for auto-fit/auto-fillgap: Fluid or fixed scale valuerowGap,columnGap: Override gap for specific axis
Fluid typography that scales smoothly.
<Text as="h1" size="text-4xl" weight="bold" color="#333">
Heading
</Text>
<Text size="text-base" lineHeight={1.6}>
Body text that scales fluidly.
</Text>Props:
size: Typography scale ('text-xs'through'text-5xl')weight:'normal' | 'medium' | 'semibold' | 'bold' | numbercolor,align,lineHeight,fontFamily
Creates flexible or fixed space between elements. Grows to fill available space by default.
{/* Push items apart */}
<Stack direction="row">
<Button>Left</Button>
<Spacer />
<Button>Right</Button>
</Stack>
{/* Fixed spacing */}
<Stack direction="column">
<Header />
<Spacer size="fluid-6" />
<Content />
</Stack>Props:
size:'auto'(default) for flexible spacing, or any CSS value / scale value for fixed spacing
Maintains consistent aspect ratios for images, videos, or any content.
{/* 16:9 video container */}
<AspectRatio ratio="16/9">
<iframe src="video-url" />
</AspectRatio>
{/* Square container */}
<AspectRatio ratio={1} maxWidth="400px">
<img src="image.jpg" alt="Square image" />
</AspectRatio>Props:
ratio: number or string like"16/9"or"4:3"(default:"16/9")maxWidth: string or number - constrain maximum width
Hidden / Show
Container-based responsive visibility control using container queries.
{/* Hide on small containers */}
<Hidden below={768}>
<DesktopNavigation />
</Hidden>
{/* Show only on small containers */}
<Show below={768}>
<MobileMenu />
</Show>
{/* Hide in a specific range */}
<Hidden below={480} above={1024}>
<TabletOnlyContent />
</Hidden>Props:
below: number - hide when container is narrower than this widthabove: number - hide when container is wider than this width
Scales smoothly between min and max values using CSS clamp():
fluid-1: 4px → 8pxfluid-2: 8px → 12pxfluid-3: 12px → 16pxfluid-4: 16px → 24pxfluid-5: 24px → 32pxfluid-6: 32px → 48pxfluid-7: 48px → 64pxfluid-8: 64px → 96pxfluid-9: 96px → 128pxfluid-10: 128px → 192px
Fixed values based on 4px (0.25rem) unit:
scale-1throughscale-10: 4px → 128px
Fluid text sizes:
text-xs,text-sm,text-base,text-lg,text-xltext-2xl,text-3xl,text-4xl,text-5xl
Components respond to their container, not just the viewport:
{/* This sidebar + content layout works ANYWHERE */}
<Stack direction="responsive">
<Box flex={1}>Sidebar</Box>
<Box flex={3}>Content</Box>
</Stack>
{/* Same component in a narrow sidebar */}
<Sidebar>
<Stack direction="responsive">
<Box flex={1}>Will stack vertically here</Box>
<Box flex={3}>Because container is narrow</Box>
</Stack>
</Sidebar>Auto-fitting grids that wrap intelligently:
<Grid columns="auto-fit" minSize="250px" gap="fluid-4">
{/* Items automatically wrap when they hit 250px minimum */}
{/* No media queries needed! */}
<Card />
<Card />
<Card />
</Grid>Spacing and typography scale smoothly, not in jumps:
{/* Padding grows smoothly from 24px to 32px as viewport grows */}
<Box padding="fluid-5">
{/* Text size grows smoothly from 32px to 40px */}
<Text size="text-3xl">Smooth scaling</Text>
</Box>React Native-style flex ratios:
<Stack direction="row">
<Box flex={1}>25% width</Box>
<Box flex={2}>50% width</Box>
<Box flex={1}>25% width</Box>
</Stack>Wren requires CSS Container Queries for layout features:
- Chrome/Edge: 105+ (September 2022)
- Safari: 16+ (September 2022)
- Firefox: 110+ (February 2023)
Wren uses progressive enhancement for fluid scales:
Modern browsers (Chromium 105+, Safari 16+, Firefox 110+):
- Scales use
cqi(container inline size) units - Components scale based on their container size
- True container-aware responsive sizing
Older browsers (with Container Queries but older):
- Scales fall back to
vw(viewport width) units - Components scale based on viewport size
- Still functional, just not container-aware for fluid scaling
| Feature | Chrome | Safari | Firefox | Notes |
|---|---|---|---|---|
| Container Queries (@container) | 105+ | 16+ | 110+ | Required |
| Container Query Units (cqi) | 105+ | 16+ | 110+ | Progressive enhancement |
| CSS clamp() | 79+ | 13.1+ | 75+ | Required |
| CSS Custom Properties | 49+ | 9.1+ | 31+ | Required |
No polyfills available - Container Queries cannot be polyfilled effectively. If you need to support older browsers, consider a viewport-based solution instead.
Wren is built on these principles:
- Intrinsic Design: Let content and context determine layout, not arbitrary breakpoints
- Container Awareness: Components should respond to their container, not just viewport
- Fluid Scales: Size and spacing should transition smoothly, not in steps
- Developer Experience: Simple, declarative API that's intuitive and type-safe
- Less Code: Eliminate repetitive responsive code
.layout {
padding: 16px;
}
@media (min-width: 640px) {
.layout { padding: 20px; }
}
@media (min-width: 768px) {
.layout { padding: 24px; }
.sidebar { width: 25%; }
.content { width: 75%; }
}
@media (min-width: 1024px) {
.layout { padding: 32px; }
}<Stack direction="responsive" spacing="fluid-4">
<Box flex={1} padding="fluid-5">Sidebar</Box>
<Box flex={3} padding="fluid-5">Content</Box>
</Stack>Result: 80% less code, minimal breakpoints, fluid scaling, container-based.
Good news: Container queries are performant in modern browsers. They don't cause layout thrashing like ResizeObserver-based solutions.
Guidelines:
- ✅ Nesting containers is fine - browsers optimize this well
- ✅ Many container queries on a page? No problem
⚠️ Avoid deeply nested container queries (10+ levels) - can impact paint performance⚠️ Container queries trigger layout recalculation when container size changes
Excellent: clamp() is highly optimized and has minimal performance impact.
- Calculations happen at paint time
- No JavaScript required
- Browser-native implementation
// ✅ Good: Fluid scales for spacing that should adapt
<Box padding="fluid-5">Content</Box>
// ✅ Good: Fixed scales for precise spacing
<Box marginBottom="scale-4">Exact 16px spacing</Box>
// ❌ Avoid: Mixing too many fluid scales can make debugging harder- Use Container sparingly at top levels - wrap entire sections, not individual components
- Prefer Grid over nested Stacks when possible - single container query context
- Fixed scales for small components - buttons, icons, etc. don't need fluid scaling
- Test on lower-end devices - container queries are relatively new, test mobile performance
Wren is designed with accessibility in mind:
✅ Text Scaling (WCAG 1.4.4):
- Fluid typography uses
remunits withclamp() - Text respects browser zoom (200%+ zoom works correctly)
- Container query units (
cqi) continue to scale during text zoom
✅ Responsive Layouts (WCAG 1.4.10):
- Content reflows without horizontal scrolling
- Container queries enable content-aware layouts
- No fixed widths that break on zoom
- Uses
display: none(removed from accessibility tree) - Screen readers won't announce hidden content
- Use for responsive UI, not critical content
// ✅ Good: Maintain semantic HTML
<Text as="h1" size="text-4xl">Heading</Text>
// ❌ Bad: Visual hierarchy without semantic meaning
<Text size="text-4xl">Heading</Text>
// ✅ Good: Provide alt text
<AspectRatio ratio="16/9">
<img src="hero.jpg" alt="Description" />
</AspectRatio>
// ✅ Good: Hide decorative content from screen readers
<Spacer aria-hidden="true" />Wren doesn't enforce colors. Ensure your chosen colors meet WCAG AA or AAA:
- AA: 4.5:1 for normal text, 3:1 for large text
- AAA: 7:1 for normal text, 4.5:1 for large text
Use tools like WebAIM Contrast Checker to verify.
// Ensure interactive elements are keyboard accessible
<Box as="button" padding="fluid-3">
Clickable Box
</Box>
// Don't hide focus indicators
// Wren doesn't override :focus stylesTraditional CSS:
- ❌ Viewport-only responsiveness
- ❌ Many breakpoints needed
- ❌ Repetitive code
- ✅ Maximum browser support
- ✅ Simple mental model
Wren:
- ✅ Container-aware responsiveness
- ✅ Minimal breakpoints (often zero custom ones)
- ✅ Declarative, reusable patterns
⚠️ Modern browser requirement⚠️ New mental model (container vs viewport)
Tailwind:
- ✅ Utility-first, highly composable
- ✅ Great DX with autocomplete
- ❌ Still viewport-based (sm:, md:, lg:)
- ❌ No container queries (yet)
- ✅ Mature ecosystem
Wren:
- ✅ Component-based, React-specific
- ✅ Container queries built-in
- ✅ Fluid scales out of the box
⚠️ Smaller community⚠️ Early stage
Every Layout / Utopia:
- ✅ Intrinsic design principles
- ✅ Fluid typography and spacing
- ✅ Framework-agnostic (CSS primitives)
- ❌ No React component abstraction
- ❌ Manual CSS implementation
Wren:
- ✅ Same principles, React components
- ✅ Pre-built component library
- ✅ TypeScript-first
⚠️ React-only- ✅ Less setup required
Chakra UI / MUI:
- ✅ Full component libraries
- ✅ Theme systems
- ✅ Large ecosystems
- ❌ Viewport-based responsive props
- ❌ Heavier bundles
- ✅ Production-ready
Wren:
- ✅ Layout primitives only (not a full UI library)
- ✅ Container-based responsive
- ✅ Smaller bundle size
⚠️ No theme system (yet)⚠️ Early stage, v0.1.0
When to use Wren: Building custom designs with container-aware layouts, want fluid scaling without breakpoints, comfortable with modern browser requirements.
When NOT to use Wren: Need IE11 support, want a full component library (buttons, modals, etc.), building for maximum browser compatibility.
respo/
├── src/
│ ├── lib/ # Core library
│ │ ├── components/ # React components
│ │ ├── core/ # Scale system, types, utils
│ │ └── styles/ # CSS foundation
│ └── docs/ # Documentation site
│ ├── sections/ # Doc sections
│ └── styles/ # Doc styles
├── package.json
├── tsconfig.json
└── vite.config.ts
npm run dev- Start documentation sitenpm run build- Build documentation sitenpm run build:lib- Build library for distributionnpm run preview- Preview production build
MIT
Built with React, TypeScript, CSS Container Queries, and CSS Custom Properties.