An opinionated, type-safe React layout library that simplifies styling and layout creation without leaving the React component context. Features responsive CSS-in-JS with Box, Grid, Flex, Stack components and more.
Built with TypeScript and Emotion CSS, @apvee/react-layout-kit leverages Emotion CSS internally for optimized runtime style generation along with a custom high-performance Slot implementation for component composition. This approach enables seamless dynamic styling based entirely on React props with minimal overhead, dramatically simplifying the React developer experience by eliminating the need for separate CSS files, complex CSS-in-JS setup, or verbose styled-components patterns.
@apvee/react-layout-kit solves common pain points in modern React development:
- 🎯 Type Safety: Full TypeScript support with autocompletion for all CSS properties
- 📱 True Responsive Design: JavaScript-driven responsive system that works with any container
- 🚀 Performance Optimized: Emotion CSS runtime optimization, debounced ResizeObserver, and memoized calculations
- ⚡ Zero Configuration: No CSS setup required - styles are generated dynamically from React props
- 🔧 Highly Configurable: Customizable breakpoints and spacing scales with module augmentation
- 🎨 Developer Experience: Intuitive API with both full CSS props and convenient shorthand properties
- 🔄 Composition Ready:
asChild
prop for seamless component composition - 🌐 SSR Compatible: Works perfectly with server-side rendering
npm install @apvee/react-layout-kit
@apvee/react-layout-kit supports flexible import patterns for optimal tree-shaking and developer experience:
// Main barrel export (recommended for most use cases)
import { Box, Flex, Stack, Grid } from "@apvee/react-layout-kit";
// Granular imports for optimal tree-shaking
import { Box } from "@apvee/react-layout-kit/components/Box";
import { Flex } from "@apvee/react-layout-kit/components/Flex";
import { Stack } from "@apvee/react-layout-kit/components/Stack";
// Type imports
import type { BoxProps, FlexProps } from "@apvee/react-layout-kit";
import type { BoxProps } from "@apvee/react-layout-kit/components/Box";
// Core utilities
import { resolveResponsiveValue } from "@apvee/react-layout-kit/core/responsive";
import { createStyles } from "@apvee/react-layout-kit/core/styling";
import { Box } from "@apvee/react-layout-kit";
function App() {
return (
<Box
$display="flex"
$gap={16}
$padding={{ xs: 8, md: 16, lg: 24 }}
$backgroundColor="blue"
$color="white"
$borderRadius={8}
>
Hello World - I'm responsive!
</Box>
);
}
import { Box, Slot } from "@apvee/react-layout-kit";
function StyledButton() {
return (
<Box asChild $padding="m" $backgroundColor="blue" $borderRadius={8}>
<button onClick={() => alert('Clicked!')}>
Button with Box styling
</button>
</Box>
);
}
@apvee/react-layout-kit follows a modular architecture for optimal developer experience and bundle optimization:
@apvee/react-layout-kit/
├── components/ # All layout components
│ ├── Box/ # Foundation component
│ ├── Flex/ # Flexbox layouts
│ ├── Stack/ # Vertical/horizontal stacking
│ ├── Grid/ # CSS Grid layouts
│ ├── SimpleGrid/ # Equal-width grids
│ ├── Container/ # Content containers
│ ├── Center/ # Centering utilities
│ ├── Group/ # Horizontal grouping
│ ├── Space/ # Spacing utilities
│ ├── AspectRatio/ # Aspect ratio maintenance
│ ├── AreaGrid/ # Named grid areas
│ └── ScrollArea/ # Scrollable containers
├── core/ # Core utilities
│ ├── styling/ # CSS generation utilities
│ ├── responsive/ # Responsive value resolution
│ ├── components/ # Slot system
│ ├── configuration/ # Global configuration
│ └── utils/ # General utilities
├── hooks/ # React hooks
├── types/ # TypeScript definitions
└── index # Main export
Export Path | Contents |
---|---|
@apvee/react-layout-kit |
All components, hooks, and utilities |
@apvee/react-layout-kit/components/Box |
Box component and types |
@apvee/react-layout-kit/components/Flex |
Flex component and types |
@apvee/react-layout-kit/components/Stack |
Stack component and types |
@apvee/react-layout-kit/components/Grid |
Grid component and types |
@apvee/react-layout-kit/components/SimpleGrid |
SimpleGrid component and types |
@apvee/react-layout-kit/components/Group |
Group component and types |
@apvee/react-layout-kit/components/Container |
Container component and types |
@apvee/react-layout-kit/components/Center |
Center component and types |
@apvee/react-layout-kit/components/AspectRatio |
AspectRatio component and types |
@apvee/react-layout-kit/components/AreaGrid |
AreaGrid component and types |
@apvee/react-layout-kit/components/ScrollArea |
ScrollArea component and types |
@apvee/react-layout-kit/components/Space |
Space component and types |
@apvee/react-layout-kit/core/styling |
CSS utilities and generators |
@apvee/react-layout-kit/core/responsive |
Responsive value utilities |
@apvee/react-layout-kit/types |
All TypeScript definitions |
- 🌳 Tree-shakable: Import only what you need for optimal bundle sizes
- 📦 Modular: Each component is self-contained with its own types
- 🔧 Maintainable: Clear separation of concerns and logical organization
- 📚 Discoverable: Intuitive import paths that reflect component hierarchy
- ⚡ Performance: Granular imports enable better build optimization
- 🎯 Type-safe: Dedicated type exports for enhanced TypeScript experience
@apvee/react-layout-kit provides a comprehensive set of layout components that work together seamlessly:
Box
- The foundation component with all CSS properties and responsive capabilities
Flex
- Flexbox container with specialized flex properties andFlex.Item
for childrenGrid
- CSS Grid container with responsive column management andGrid.Col
for itemsStack
- Vertical or horizontal stacking with consistent spacingSimpleGrid
- Equal-width grid with responsive column countsAreaGrid
- Named CSS Grid areas withAreaGrid.Item
for semantic layoutsContainer
- Content wrapper with max-width and centeringCenter
- Flexbox centering utility for both inline and block contentAspectRatio
- Maintains consistent aspect ratios for media contentGroup
- Horizontal grouping with gap and overflow handlingSpace
- Invisible spacing utility for consistent whitespaceScrollArea
- Scrollable container with custom scrollbar styling and virtualization support
Slot
- Powerful component composition primitive for theasChild
pattern with advanced prop mergingSlottable
- Marker component for advanced slot composition scenariosuseSlot
- Hook for programmatic slot detection and manipulation
All components share the same responsive system, spacing scale, and styling capabilities through the Box
foundation.
The Box
component is the foundation of the library. It's a polymorphic component that can render as any HTML element while providing powerful styling capabilities.
- Universal CSS Properties: Every CSS property is available with a
$
prefix - Responsive Values: Use breakpoint objects for responsive design
- Automatic Width Measurement: Built-in ResizeObserver for container-aware responsive behavior
- Component Composition: Render as any element using the
asChild
prop - Performance Optimized: Memoized computations and debounced measurements
Prop | Type | Description |
---|---|---|
asChild |
boolean |
Render as child element using internal Slot |
containerWidth |
number |
Programmatic container width for responsive calculations - use with useContainerWidth hook or when you have a parent container width to provide |
styleReset |
boolean |
Apply basic style reset (box-sizing: border-box) |
Prop | Type | Description |
---|---|---|
m |
ResponsiveValue<SpacingValue> |
Margin (all sides) |
mt |
ResponsiveValue<SpacingValue> |
Margin top |
mb |
ResponsiveValue<SpacingValue> |
Margin bottom |
ml |
ResponsiveValue<SpacingValue> |
Margin left |
mr |
ResponsiveValue<SpacingValue> |
Margin right |
ms |
ResponsiveValue<SpacingValue> |
Margin inline start (logical property) |
me |
ResponsiveValue<SpacingValue> |
Margin inline end (logical property) |
mx |
ResponsiveValue<SpacingValue> |
Margin inline (left + right) |
my |
ResponsiveValue<SpacingValue> |
Margin block (top + bottom) |
Prop | Type | Description |
---|---|---|
p |
ResponsiveValue<SpacingValue> |
Padding (all sides) |
pt |
ResponsiveValue<SpacingValue> |
Padding top |
pb |
ResponsiveValue<SpacingValue> |
Padding bottom |
pl |
ResponsiveValue<SpacingValue> |
Padding left |
pr |
ResponsiveValue<SpacingValue> |
Padding right |
ps |
ResponsiveValue<SpacingValue> |
Padding inline start (logical property) |
pe |
ResponsiveValue<SpacingValue> |
Padding inline end (logical property) |
px |
ResponsiveValue<SpacingValue> |
Padding inline (left + right) |
py |
ResponsiveValue<SpacingValue> |
Padding block (top + bottom) |
Prop | Type | Description |
---|---|---|
w |
ResponsiveValue<Width> |
Width - accepts CSS values |
miw |
ResponsiveValue<MinWidth> |
Minimum width |
maw |
ResponsiveValue<MaxWidth> |
Maximum width |
h |
ResponsiveValue<Height> |
Height - accepts CSS values |
mih |
ResponsiveValue<MinHeight> |
Minimum height |
mah |
ResponsiveValue<MaxHeight> |
Maximum height |
Prop | Type | Description |
---|---|---|
top |
ResponsiveValue<Top> |
Top position - uses CSS values |
left |
ResponsiveValue<Left> |
Left position - uses CSS values |
bottom |
ResponsiveValue<Bottom> |
Bottom position - uses CSS values |
right |
ResponsiveValue<Right> |
Right position - uses CSS values |
All CSS properties are available with a $
prefix and support responsive values:
Property Category | Examples |
---|---|
Layout | $display , $position , $float , $clear |
Flexbox | $flexDirection , $justifyContent , $alignItems , $flex , $flexGrow |
Grid | $gridTemplateColumns , $gridArea , $justifyItems , $alignContent |
Spacing | $margin , $padding , $gap , $rowGap , $columnGap |
Sizing | $width , $height , $minWidth , $maxHeight , $boxSizing |
Typography | $fontSize , $fontWeight , $lineHeight , $textAlign , $color |
Visual | $backgroundColor , $border , $borderRadius , $boxShadow , $opacity |
Positioning | $top , $left , $bottom , $right , $zIndex |
Transform | $transform , $transformOrigin , $rotate , $scale , $translate |
Animation | $transition , $animation , $transitionDuration |
Every CSS property is available with a $
prefix, providing full type safety and autocompletion:
<Box
// Layout
$display="flex"
$flexDirection="column"
$alignItems="center"
$justifyContent="space-between"
// Spacing
$padding={24}
$margin="auto"
$gap={16}
// Visual
$backgroundColor="#f0f8ff"
$borderRadius={12}
$boxShadow="0 4px 12px rgba(0,0,0,0.1)"
$border="1px solid #e1e5e9"
// Typography
$fontSize={18}
$fontWeight="600"
$color="#333"
$textAlign="center"
// Positioning
$position="relative"
$top={0}
$zIndex={10}
>
Fully styled content
</Box>
The Flex
component provides comprehensive flexbox layout capabilities with responsive support and a specialized Flex.Item
sub-component.
- Complete Flexbox Control: All CSS flexbox properties available
- Flex.Item Sub-component: Individual flex item control with grow, shrink, basis
- Advanced Gap Control: Separate row and column gaps
- Responsive Values: Every property supports responsive breakpoint objects
- Container-aware: Automatic width measurement for responsive calculations
Prop | Type | Description |
---|---|---|
align |
ResponsiveValue<AlignItems> |
Cross-axis alignment of elements |
justify |
ResponsiveValue<JustifyContent> |
Main-axis alignment of elements |
direction |
ResponsiveValue<FlexDirection> |
Flex layout direction |
wrap |
ResponsiveValue<FlexWrap> |
Flex items wrapping behavior |
gap |
ResponsiveValue<SpacingValue> |
Space between all elements |
rowGap |
ResponsiveValue<SpacingValue> |
Space between rows |
columnGap |
ResponsiveValue<SpacingValue> |
Space between columns |
Prop | Type | Description |
---|---|---|
flex |
ResponsiveValue<Flex> |
Flex shorthand property |
grow |
ResponsiveValue<FlexGrow> |
Element's ability to grow |
shrink |
ResponsiveValue<FlexShrink> |
Element's ability to shrink |
basis |
ResponsiveValue<FlexBasis> |
Element's base size |
alignSelf |
ResponsiveValue<AlignSelf> |
Individual element alignment |
order |
ResponsiveValue<Order> |
Visual order of element |
// Basic flex container
<Flex align="center" justify="space-between" gap="m">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</Flex>
// Column layout with responsive direction
<Flex
direction={{ xs: "column", md: "row" }}
align={{ xs: "stretch", md: "center" }}
gap={{ xs: "s", md: "l" }}
>
<div>Responsive Item 1</div>
<div>Responsive Item 2</div>
</Flex>
// Advanced flex items
<Flex gap="m">
<Flex.Item flex={1}>Grows to fill space</Flex.Item>
<Flex.Item shrink={0} basis="200px">Fixed 200px width</Flex.Item>
<Flex.Item grow={2} alignSelf="flex-end">Grows 2x, aligns to end</Flex.Item>
</Flex>
The Stack
component creates vertical stacking layouts with consistent spacing and alignment using CSS flexbox with flex-direction: column
.
- Vertical Stacking: Optimized for vertical layouts like forms, content sections, and card lists
- Consistent Spacing: Automatic gap management between stacked items
- Cross-axis Alignment: Control horizontal alignment of items within the stack
- Responsive Properties: All properties support responsive values
- Semantic HTML: Works with any child elements
Prop | Type | Description |
---|---|---|
align |
ResponsiveValue<AlignItems> |
Cross-axis (horizontal) alignment of elements |
justify |
ResponsiveValue<JustifyContent> |
Main-axis (vertical) alignment of elements |
gap |
ResponsiveValue<SpacingValue> |
Space between stacked elements |
// Basic vertical stack with consistent spacing
<Stack gap="md" align="center">
<h1>Title</h1>
<p>Description</p>
<button>Action</button>
</Stack>
// Form layout with vertical stacking
<Stack gap="md" align="stretch">
<input type="text" placeholder="Name" />
<input type="email" placeholder="Email" />
<textarea placeholder="Message" />
<button type="submit">Submit</button>
</Stack>
// Responsive vertical stack with dynamic spacing
<Stack
gap={{ xs: "sm", md: "lg" }}
align={{ xs: "stretch", md: "center" }}
>
<div>Stack Item 1</div>
<div>Stack Item 2</div>
<div>Stack Item 3</div>
</Stack>
The Container
component centers content horizontally and controls maximum width for consistent page layouts.
- Automatic Centering: Uses auto margins for horizontal centering
- Max Width Control: Configurable maximum width with responsive values
- Fluid Mode: Full-width option for dashboard layouts
- Built-in Padding: Consistent horizontal padding for readability
Prop | Type | Description |
---|---|---|
size |
ResponsiveValue<number> |
Maximum width in pixels |
fluid |
ResponsiveValue<boolean> |
Full width mode |
// Default container (1200px max width)
<Container>
<h1>Centered Content</h1>
<p>This content is automatically centered and has a max width of 1200px</p>
</Container>
// Responsive container sizes
<Container size={{ xs: 320, sm: 480, md: 640, lg: 1024, xl: 1366 }}>
<div>Responsive container content</div>
</Container>
// Fluid container for full-width layouts
<Container fluid>
<div>Full width content for dashboards</div>
</Container>
The Grid
component provides CSS Grid layout capabilities with flexible column management and responsive behavior.
- CSS Grid Layout: Full CSS Grid support with responsive columns
- Grid.Col Sub-component: Individual grid item control
- Flexible Columns: Dynamic column count and sizing
- Responsive Layout: Container-aware responsive behavior
Prop | Type | Description |
---|---|---|
columns |
ResponsiveValue<number> |
Number of columns |
gutter |
ResponsiveValue<SpacingValue> |
Space between elements |
align |
ResponsiveValue<AlignItems> |
Vertical alignment |
justify |
ResponsiveValue<JustifyContent> |
Horizontal alignment |
Prop | Type | Description |
---|---|---|
span |
ResponsiveValue<number> |
Number of columns to span |
offset |
ResponsiveValue<number> |
Column offset |
// Basic 3-column grid
<Grid columns={3} gutter="m">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</Grid>
// Responsive grid with column spans
<Grid columns={{ xs: 1, sm: 2, md: 3, lg: 4 }} gutter="l">
<Grid.Col span={{ xs: 1, md: 2 }}>Wide item</Grid.Col>
<Grid.Col>Regular item</Grid.Col>
<Grid.Col>Regular item</Grid.Col>
</Grid>
The SimpleGrid
component creates equal-width grid layouts with responsive column counts.
- Equal Width Columns: Automatic equal-width grid items
- Responsive Columns: Dynamic column count based on breakpoints
- Simple API: Minimal configuration for common grid layouts
- Auto-fit Behavior: Intelligent column fitting
Prop | Type | Description |
---|---|---|
cols |
ResponsiveValue<number> |
Number of columns |
spacing |
ResponsiveValue<SpacingValue> |
Space between elements |
minChildWidth |
ResponsiveValue<number> |
Minimum width of children |
// Simple equal-width grid
<SimpleGrid cols={3} spacing="m">
<div>Card 1</div>
<div>Card 2</div>
<div>Card 3</div>
</SimpleGrid>
// Responsive column count
<SimpleGrid
cols={{ xs: 1, sm: 2, md: 3, lg: 4 }}
spacing={{ xs: "s", md: "l" }}
>
<div>Responsive Card 1</div>
<div>Responsive Card 2</div>
<div>Responsive Card 3</div>
<div>Responsive Card 4</div>
</SimpleGrid>
The Center
component provides perfect centering for content using flexbox.
- Perfect Centering: Both horizontal and vertical centering
- Inline/Block Mode: Support for both inline-flex and flex display
- Responsive Behavior: Responsive inline/block switching
- Semantic HTML: Works with any child content
Prop | Type | Description |
---|---|---|
inline |
ResponsiveValue<boolean> |
Use inline-flex instead of flex |
// Center content in a container
<Center $height="200px">
<button>Perfectly Centered Button</button>
</Center>
// Inline centering for text elements
<Center inline>
<span>Inline centered text</span>
</Center>
The AspectRatio
component maintains consistent aspect ratios for media content.
- Consistent Ratios: Maintains width/height ratios perfectly
- Responsive Ratios: Different ratios at different breakpoints
- Media Perfect: Ideal for images, videos, maps, and embeds
- CSS Padding Technique: Uses reliable CSS padding-bottom method
Prop | Type | Description |
---|---|---|
ratio |
ResponsiveValue<number> |
Aspect ratio as width/height |
// 16:9 video aspect ratio
<AspectRatio ratio={16/9}>
<iframe src="video-url" style={{ width: '100%', height: '100%' }} />
</AspectRatio>
// Responsive aspect ratios
<AspectRatio ratio={{ xs: 1, md: 16/9 }}>
<img src="image.jpg" style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
</AspectRatio>
The Group
component creates horizontal flex layouts with advanced overflow handling.
- Horizontal Grouping: Specialized for horizontal layouts
- Overflow Prevention: Smart overflow handling for button groups
- Flexible Growth: Optional grow behavior for items
- Responsive Wrapping: Configurable wrap behavior
Prop | Type | Description |
---|---|---|
align |
ResponsiveValue<AlignItems> |
Cross-axis alignment of elements |
gap |
ResponsiveValue<SpacingValue> |
Space between elements |
grow |
ResponsiveValue<boolean> |
Element growth behavior |
justify |
ResponsiveValue<JustifyContent> |
Main-axis alignment of elements |
preventGrowOverflow |
ResponsiveValue<boolean> |
Prevent overflow with grow |
wrap |
ResponsiveValue<FlexWrap> |
Wrapping behavior |
// Button group
<Group gap="s" wrap="nowrap">
<button>Save</button>
<button>Cancel</button>
<button>Delete</button>
</Group>
// Responsive toolbar
<Group
gap={{ xs: "xs", md: "s" }}
justify={{ xs: "center", md: "flex-start" }}
wrap={{ xs: "wrap", md: "nowrap" }}
>
<button>Action 1</button>
<button>Action 2</button>
<button>Action 3</button>
</Group>
The Space
component provides invisible spacing utility for consistent whitespace.
- Invisible Spacing: Creates space without visual elements
- Width/Height Control: Both horizontal and vertical spacing
- Responsive Spacing: Dynamic spacing based on breakpoints
- Layout Utility: Perfect for section spacing and layout rhythm
Prop | Type | Description |
---|---|---|
w |
ResponsiveValue<SpacingValue> |
Horizontal spacing |
h |
ResponsiveValue<SpacingValue> |
Vertical spacing |
// Vertical section spacing
<div>
<h1>Section 1</h1>
<Space h="xl" />
<h2>Section 2</h2>
<Space h="l" />
<p>Content with consistent spacing</p>
</div>
// Responsive spacing
<div>
<div>Content Block 1</div>
<Space h={{ xs: "m", md: "xl" }} />
<div>Content Block 2</div>
</div>
The ScrollArea
component provides custom scrollbars with native scrolling performance and responsive design capabilities.
- Native Performance: Uses native scrolling with custom overlay scrollbars
- Responsive Sizing: Scrollbar size adapts to different screen sizes
- Multiple Visibility Modes: hover, always, or scroll-based visibility
- RTL Support: Full right-to-left language support
- Customizable Styling: Custom colors, sizes, and border radius
- Accessible: Minimum touch targets and keyboard navigation
Prop | Type | Description |
---|---|---|
asChild |
boolean |
Render as child element using Slot pattern |
size |
ResponsiveValue<'small' | 'medium' | 'large'> |
Scrollbar thickness (default: 'small') |
radius |
'none' | 'small' | 'medium' | 'large' | 'full' |
Border radius (default: 'small') |
scrollbars |
'vertical' | 'horizontal' | 'both' |
Which scrollbars to show (default: 'both') |
type |
'hover' | 'always' | 'scroll' |
Visibility behavior (default: 'hover') |
scrollHideDelay |
number |
Hide delay in ms (default: 600) |
dir |
'ltr' | 'rtl' |
Text direction (default: 'ltr') |
trackColor |
string |
Scrollbar track background color |
thumbColor |
string |
Scrollbar thumb color |
thumbHoverColor |
string |
Thumb color on hover |
thumbActiveColor |
string |
Thumb color when pressed |
// Basic scrollable content
<ScrollArea style={{ height: 300, width: 400 }}>
<div style={{ height: 1000 }}>
Very long content that will scroll...
{Array.from({ length: 100 }, (_, i) => (
<div key={i}>Item {i + 1}</div>
))}
</div>
</ScrollArea>
// Responsive scrollbar size
<ScrollArea
size={{ xs: 'small', md: 'medium', lg: 'large' }}
type="always"
>
<div style={{ height: 500, width: 800 }}>
Content with responsive scrollbars
</div>
</ScrollArea>
// Custom styling
<ScrollArea
thumbColor="rgba(0, 123, 255, 0.5)"
thumbHoverColor="rgba(0, 123, 255, 0.8)"
trackColor="rgba(0, 0, 0, 0.1)"
radius="large"
type="hover"
scrollHideDelay={300}
>
<div style={{ height: 400 }}>
Styled scrollable content
</div>
</ScrollArea>
// Horizontal-only scrolling
<ScrollArea scrollbars="horizontal" style={{ width: 300 }}>
<div style={{ width: 800, whiteSpace: 'nowrap' }}>
Wide content that scrolls horizontally...
</div>
</ScrollArea>
// Composition with asChild
<ScrollArea asChild>
<section className="custom-scrollable-section">
<div style={{ height: 600 }}>
Scrollable section content
</div>
</section>
</ScrollArea>
// With useContainerWidth for responsive behavior
function ResponsiveScrollArea() {
const containerRef = React.useRef<HTMLDivElement>(null);
const containerWidth = useContainerWidth(containerRef);
return (
<div ref={containerRef} style={{ width: '100%' }}>
<ScrollArea
size={{ xs: 'small', md: 'medium' }}
containerWidth={containerWidth}
>
<div style={{ height: 500 }}>
Container-aware scrollable content
</div>
</ScrollArea>
</div>
);
}
The Slot
component enables powerful component composition using the asChild
pattern, allowing props to be passed through to child elements while merging refs, event handlers, and styles intelligently.
- Seamless Composition: Pass props to child elements without wrapper divs
- Advanced Prop Merging: Intelligent merging of event handlers, className, style, and refs
- Slottable Support: Advanced composition scenarios with the
Slottable
component - Zero Dependencies: Standalone implementation optimized for performance and SPFx compatibility
- Full TypeScript Support: Complete type safety with prop merging and composition
Prop | Type | Description |
---|---|---|
children |
React.ReactNode |
Child element to receive props |
Prop | Type | Description |
---|---|---|
children |
React.ReactNode |
Content to be marked as slottable |
Returns an object with utilities for working with Slot components programmatically:
Return Property | Type | Description |
---|---|---|
ref |
React.RefCallback<HTMLElement> |
Ref callback for slot detection |
slotRef |
HTMLElement | null |
Current slot element reference |
isSlot |
boolean |
Whether element is a Slot component |
// Basic slot usage - props merge with button
<Slot
onClick={handleClick}
className="custom-class"
style={{ margin: '10px' }}
>
<button className="btn" style={{ padding: '5px' }}>
Click me
</button>
</Slot>
// Renders: <button onClick={handleClick} className="custom-class btn" style={{ margin: '10px', padding: '5px' }}>
// Advanced composition with Box
<Box asChild $padding="m" $backgroundColor="blue" $borderRadius={8}>
<button onClick={handleSubmit}>
Styled Button with Box props
</button>
</Box>
// Multiple prop merging
<Slot
onClick={handlePrimary}
onFocus={handleFocus}
className="wrapper-class"
style={{ fontSize: '16px' }}
>
<CustomButton
onClick={handleSecondary}
className="button-class"
style={{ color: 'red' }}
>
Merged Props Button
</CustomButton>
</Slot>
// Both onClick handlers will be called, classes and styles merged
// Using with Slottable for complex scenarios
<Slot onClick={handleClick}>
<Slottable>
<ComplexComponent>
<NestedContent />
</ComplexComponent>
</Slottable>
</Slot>
// useSlot hook for programmatic detection
function CustomComponent({ element }) {
const { ref, slotRef, isSlot } = useSlot(element);
return (
<div ref={ref}>
{isSlot ? 'This is a Slot component' : 'Regular component'}
{slotRef && <p>Slot element: {slotRef.tagName}</p>}
</div>
);
}
The AreaGrid
component provides CSS Grid layouts using named grid areas for semantic, flexible layouts.
- Named Grid Areas: Use semantic names like "header", "sidebar", "main", "footer"
- AreaGrid.Item Sub-component: Positions items in named areas with individual alignment
- Responsive Restructuring: Completely change layout structure at different breakpoints
- Full Grid Control: Complete control over rows, columns, gaps, and alignment
- Context-aware Rendering: Items only render when their area exists in current layout
Prop | Type | Description |
---|---|---|
areas |
ResponsiveValue<string> |
Grid-template-areas definition |
rows |
ResponsiveValue<string> |
Grid-template-rows sizing |
columns |
ResponsiveValue<string> |
Grid-template-columns sizing |
gap |
ResponsiveValue<SpacingValue> |
Space between grid items |
justifyItems |
ResponsiveValue<JustifyItems> |
Horizontal alignment of items |
alignItems |
ResponsiveValue<AlignItems> |
Vertical alignment of items |
justifyContent |
ResponsiveValue<JustifyContent> |
Horizontal alignment of content |
alignContent |
ResponsiveValue<AlignContent> |
Vertical alignment of content |
Prop | Type | Description |
---|---|---|
area |
ResponsiveValue<string> |
Grid area assignment |
justifySelf |
ResponsiveValue<JustifySelf> |
Individual horizontal alignment |
alignSelf |
ResponsiveValue<AlignSelf> |
Individual vertical alignment |
// Basic page layout
<AreaGrid
areas='"header header header" "sidebar main main" "footer footer footer"'
rows="auto 1fr auto"
columns="200px 1fr 1fr"
gap="m"
>
<AreaGrid.Item area="header">Header Content</AreaGrid.Item>
<AreaGrid.Item area="sidebar">Sidebar Content</AreaGrid.Item>
<AreaGrid.Item area="main">Main Content</AreaGrid.Item>
<AreaGrid.Item area="footer">Footer Content</AreaGrid.Item>
</AreaGrid>
// Responsive layout restructuring
<AreaGrid
areas={{
xs: '"header" "main" "sidebar" "footer"', // Mobile: stacked vertically
md: '"header header" "sidebar main" "footer footer"' // Desktop: sidebar layout
}}
rows={{ xs: "auto auto auto auto", md: "auto 1fr auto" }}
columns={{ xs: "1fr", md: "200px 1fr" }}
gap={{ xs: "s", md: "l" }}
>
<AreaGrid.Item area="header">Responsive Header</AreaGrid.Item>
<AreaGrid.Item area="sidebar">Responsive Sidebar</AreaGrid.Item>
<AreaGrid.Item area="main">Responsive Main Content</AreaGrid.Item>
<AreaGrid.Item area="footer">Responsive Footer</AreaGrid.Item>
</AreaGrid>
// Advanced dashboard layout
<AreaGrid
areas={`
"nav nav nav nav"
"sidebar main main widgets"
"sidebar charts charts widgets"
"footer footer footer footer"
`}
columns="180px 1fr 1fr 200px"
rows="60px 1fr 1fr 50px"
gap="s"
>
<AreaGrid.Item area="nav" justifySelf="stretch">Navigation</AreaGrid.Item>
<AreaGrid.Item area="sidebar">Dashboard Sidebar</AreaGrid.Item>
<AreaGrid.Item area="main">Main Dashboard</AreaGrid.Item>
<AreaGrid.Item area="widgets">Widget Panel</AreaGrid.Item>
<AreaGrid.Item area="charts">Chart Area</AreaGrid.Item>
<AreaGrid.Item area="footer">Dashboard Footer</AreaGrid.Item>
</AreaGrid>
Responsive values allow you to specify different values for different screen sizes using breakpoint objects. This is more powerful than traditional CSS media queries because it's container-aware and JavaScript-driven.
type ResponsiveValue<T> = T | Partial<Record<BreakpointKey, T>>;
The library automatically measures container width and applies the appropriate value based on your breakpoint configuration:
<Box
$padding={{
xs: 8, // 0px and up
sm: 12, // 480px and up
md: 16, // 640px and up
lg: 24, // 1024px and up
xl: 32, // 1366px and up
}}
$fontSize={{
xs: 14,
md: 16,
lg: 18,
}}
$backgroundColor={{
xs: "lightblue",
md: "lightgreen",
lg: "lightcoral",
}}
>
I change based on my container size, not just viewport!
</Box>
Responsive values use a mobile-first approach. Each breakpoint applies from that width up until a larger breakpoint is reached:
<Box $padding={{ xs: 8, lg: 24 }}>
{/* 8px padding from 0-1023px, 24px padding from 1024px+ */}
</Box>
Unlike CSS media queries that respond to viewport size, responsive values respond to the actual container width:
function SidebarCard() {
return (
<div style={{ width: "300px" }}>
{" "}
{/* Small container */}
<Box
$padding={{ xs: 8, md: 16, lg: 24 }}
$fontSize={{ xs: 12, md: 14, lg: 16 }}
>
{/* Uses xs values because container is 300px wide */}
Small container content
</Box>
</div>
);
}
function MainContent() {
return (
<div style={{ width: "800px" }}>
{" "}
{/* Large container */}
<Box
$padding={{ xs: 8, md: 16, lg: 24 }}
$fontSize={{ xs: 12, md: 14, lg: 16 }}
>
{/* Uses md values because container is 800px wide */}
Large container content
</Box>
</div>
);
}
Short props provide a more concise and familiar syntax for common CSS properties, especially spacing. They're inspired by popular libraries like Chakra UI and Tailwind CSS.
// Individual sides
m = "m"; // margin (all sides)
mt = "s"; // margin-top
mr = "l"; // margin-right
mb = "m"; // margin-bottom
ml = "xs"; // margin-left
// Logical properties (recommended for internationalization)
ms = "s"; // margin-inline-start (left in LTR, right in RTL)
me = "m"; // margin-inline-end (right in LTR, left in RTL)
mx = "l"; // margin-inline (left + right)
my = "m"; // margin-block (top + bottom)
// Individual sides
p = "m"; // padding (all sides)
pt = "s"; // padding-top
pr = "l"; // padding-right
pb = "m"; // padding-bottom
pl = "xs"; // padding-left
// Logical properties
ps = "s"; // padding-inline-start
pe = "m"; // padding-inline-end
px = "l"; // padding-inline (left + right)
py = "m"; // padding-block (top + bottom)
w = "200px"; // width (uses CSS values, not spacing scale)
h = "l"; // height (uses spacing scale)
miw = "m"; // min-width (uses spacing scale)
maw = "xl"; // max-width (uses spacing scale)
mih = "s"; // min-height (uses spacing scale)
mah = "l"; // max-height (uses spacing scale)
top = "10px"; // top (uses CSS values, not spacing scale)
left = "20px"; // left
bottom = "0"; // bottom
right = "auto"; // right
Short props work seamlessly with responsive values:
<Box
p={{ xs: "s", md: "m", lg: "l" }} // responsive padding
mx={{ xs: "xs", lg: "xl" }} // responsive horizontal margin
h={{ xs: "s", md: "m" }} // responsive height (using spacing scale)
w={{ xs: "100px", md: "200px" }} // responsive width (using CSS values)
>
Responsive short props
</Box>
Most spacing-related short props (margin, padding, spacing-specific size props) automatically use the spacing scale, while width/height and position props use CSS values directly:
<Box
p="m" // Uses spacing scale: resolves to 16px by default
m="l" // Uses spacing scale: resolves to 24px by default
h="l" // Uses spacing scale: resolves to 24px by default
w="200px" // CSS value: uses exactly "200px"
top="10px" // CSS value: uses exactly "10px"
left="2rem" // CSS value: uses exactly "2rem"
>
Mixed spacing types
</Box>
When both dollar props and short props define the same CSS property, dollar props take precedence:
<Box
p="l" // padding: 24px from spacing scale
$padding="8px" // Wins! Final padding: 8px
>
Dollar props always win
</Box>
The useContainerWidth
hook provides precise, debounced container width measurement using ResizeObserver. Internally, it's a wrapper around the more fundamental useElementWidth
hook:
import { useContainerWidth, useElementWidth } from "@apvee/react-layout-kit";
function ResponsiveCard() {
const containerRef = React.useRef<HTMLDivElement>(null);
const width = useContainerWidth(containerRef, {
debounceMs: 16, // 60fps updates (default)
});
return (
<Box
ref={containerRef}
containerWidth={width} // Use measured width for responsive calculations
$padding={{ xs: 8, md: 16, lg: 24 }}
$backgroundColor={width < 400 ? "lightblue" : "lightgreen"}
>
Container width: {width}px
<div>Responsive based on actual container size!</div>
</Box>
);
}
interface UseContainerWidthOptions {
disabled?: boolean; // Disable measurement
debounceMs?: number; // Debounce delay (default: 16ms for 60fps)
}
// Examples
const width1 = useContainerWidth(ref); // Default options
const width2 = useContainerWidth(ref, { debounceMs: 32 }); // 30fps updates
const width3 = useContainerWidth(ref, { disabled: true }); // Disabled
Container-aware responsive design is more powerful than viewport-based media queries:
// Traditional CSS media queries - responds to viewport
@media (max-width: 640px) {
.card { padding: 8px; }
}
// Container-aware responsive - responds to actual container
<Box $padding={{ xs: 8, md: 16 }}>
{/* Automatically uses correct padding based on container size */}
</Box>
This enables true component-level responsive design, where the same component can behave differently in different contexts.
The containerWidth
prop allows you to provide container width programmatically rather than relying on automatic measurement. This is useful when:
- Using the useContainerWidth hook to measure a parent container
- You have programmatic access to a parent container's dimensions
- Performance optimization when you know the container width
function ParentWithChild() {
const parentRef = React.useRef<HTMLDivElement>(null);
const parentWidth = useContainerWidth(parentRef);
return (
<div ref={parentRef} style={{ width: '60%' }}>
<Box
containerWidth={parentWidth} // Use measured parent width
$padding={{ xs: 8, md: 16, lg: 24 }}
$fontSize={{ xs: 14, md: 16, lg: 18 }}
>
Child responds to parent container size
</Box>
</div>
);
}
function DynamicLayout({ sidebarOpen }) {
// Calculate available width based on sidebar state
const availableWidth = sidebarOpen ? window.innerWidth - 300 : window.innerWidth;
return (
<Box
containerWidth={availableWidth}
$padding={{ xs: 8, md: 16, lg: 24 }}
>
Layout adapts to available space
</Box>
);
}
mergeClasses
is a re-export of Emotion's cx
function for combining class names safely:
import { mergeClasses } from "@apvee/react-layout-kit";
const baseClass = "base-styles";
const conditionalClass = isActive ? "active" : undefined;
const emotionClass = css({ color: "red" });
const combinedClass = mergeClasses(
baseClass,
conditionalClass, // undefined values are filtered out
emotionClass,
"additional-class"
);
createStyles
is a re-export of Emotion's css
function for creating CSS classes:
import { createStyles, mergeClasses } from "@apvee/react-layout-kit";
// Create reusable style classes
const buttonBase = createStyles({
padding: "12px 24px",
borderRadius: "6px",
border: "none",
cursor: "pointer",
fontWeight: 600,
});
const primaryButton = createStyles({
backgroundColor: "#007bff",
color: "white",
"&:hover": {
backgroundColor: "#0056b3",
},
});
const secondaryButton = createStyles({
backgroundColor: "#6c757d",
color: "white",
"&:hover": {
backgroundColor: "#545b62",
},
});
// Use with Box component
function CustomButton({ variant = "primary", children, ...props }) {
const variantClass = variant === "primary" ? primaryButton : secondaryButton;
return (
<Box asChild className={mergeClasses(buttonBase, variantClass)} {...props}>
<button>{children}</button>
</Box>
);
}
The utility functions work seamlessly with the Box component:
const myCustomStyles = createStyles({
border: "2px solid #007bff",
"&:hover": {
borderColor: "#0056b3",
},
});
<Box
className={mergeClasses(myCustomStyles, "additional-class")}
$padding="m"
$borderRadius={8}
>
Combined custom and Box styles
</Box>;
The library comes with sensible default breakpoints:
const defaultBreakpoints = {
xs: 0, // Mobile first
sm: 480, // Small mobile
md: 640, // Tablet
lg: 1024, // Desktop
xl: 1366, // Large desktop
xxl: 1920, // Extra large desktop
};
The library includes a default spacing scale:
const defaultSpacing = {
none: 0,
xs: 4, // 0.25rem equivalent
sm: 8, // 0.5rem equivalent
md: 12, // 0.75rem equivalent
lg: 16, // 1rem equivalent
xl: 20, // 1.25rem equivalent
xxl: 24, // 1.5rem equivalent
xxxl: 32, // 2rem equivalent
};
You can extend the default breakpoints by using TypeScript module augmentation and runtime configuration:
Create a type declaration file in your project:
// types/react-box.d.ts
import "@apvee/react-layout-kit";
declare module "@apvee/react-layout-kit" {
interface BreakpointDefs {
// Add custom breakpoints while keeping defaults
tablet: number;
"2xl": number;
"3xl": number;
mobile: number;
}
}
Configure the actual breakpoint values at runtime:
// config/box-config.ts
import { configureBox } from "@apvee/react-layout-kit";
configureBox({
breakpoints: {
// Keep defaults and add custom ones
xs: 0,
mobile: 360, // Custom mobile breakpoint
sm: 480,
tablet: 600, // Custom tablet breakpoint
md: 640,
lg: 1024,
xl: 1366,
xxl: 1920,
"3xl": 2560, // Custom extra large
},
});
Now you can use your custom breakpoints with full type safety:
<Box
$padding={{
xs: 8,
mobile: 12, // Custom breakpoint with autocomplete!
tablet: 16, // Custom breakpoint with autocomplete!
md: 20,
"2xl": 32, // Custom breakpoint with autocomplete!
"3xl": 40, // Custom breakpoint with autocomplete!
}}
>
Custom responsive behavior
</Box>
Similarly, you can extend the spacing scale:
// types/react-box.d.ts
import "@apvee/react-layout-kit";
declare module "@apvee/react-layout-kit" {
interface SpacingDefs {
// Add custom spacing tokens
xxs: string | number;
xxxl: string | number;
"0": string | number;
"1": string | number;
"2": string | number;
"4": string | number;
"8": string | number;
}
}
// config/box-config.ts
import { configureBox } from "@apvee/react-layout-kit";
configureBox({
spacing: {
// Keep defaults and add custom ones
"0": 0,
none: 0,
xxs: 2, // 0.125rem
xs: 4,
sm: 8,
md: 12,
lg: 16,
xl: 20,
xxl: 24,
xxxl: 32, // 2rem
"4xl": 48, // 3rem
},
});
<Box
p={{
xs: "xxs", // Custom spacing with autocomplete!
md: "4", // Numeric spacing tokens
lg: "xxxl", // Custom large spacing
}}
m="2" // Numeric spacing token
>
Custom spacing system
</Box>
You can use different units and even responsive spacing values:
configureBox({
spacing: {
none: 0,
xxs: "0.125rem", // rem units
xs: "0.25rem",
s: "0.5rem",
m: "1rem",
l: "1.5rem",
xl: "2rem",
xxl: "3rem",
fluid: "clamp(1rem, 2vw, 2rem)", // CSS clamp for fluid spacing
golden: "1.618rem", // Golden ratio spacing
},
});
- Configure Early: Set up configuration before rendering any Box components
- Use Module Augmentation: Always extend types for better DX
- Keep Consistency: Use consistent naming patterns for breakpoints and spacing
- Document Your Scale: Create documentation for your custom spacing and breakpoints
// app/setup.ts - Configure before app starts
import { configureBox } from "@apvee/react-layout-kit";
export function setupBoxConfiguration() {
configureBox({
breakpoints: {
xs: 0,
sm: 480,
md: 640,
lg: 1024,
xl: 1366,
xxl: 1920,
},
spacing: {
none: 0,
xs: 4,
sm: 8,
md: 12,
lg: 16,
xl: 20,
xxl: 24,
xxxl: 32,
},
});
}
// main.tsx
import { setupBoxConfiguration } from "./app/setup";
setupBoxConfiguration(); // Call before rendering
The asChild
prop allows the Box component to render as any HTML element or React component while preserving all its styling capabilities. This is powered by an internal high-performance Slot implementation.
// Render as a button
<Box asChild $padding="m" $backgroundColor="blue" $color="white" $borderRadius={6}>
<button onClick={() => alert('Clicked!')}>
Styled Button
</button>
</Box>
// Render as a link
<Box asChild $display="inline-block" $padding="s" $textDecoration="none">
<a href="/about">
Styled Link
</a>
</Box>
// Render as an article
<Box asChild $maxWidth={600} $margin="auto" $padding="l">
<article>
<h1>Article Title</h1>
<p>Article content...</p>
</article>
</Box>
// Custom button component with Box styling
function CustomButton({ variant, children, ...props }) {
const variantStyles = {
primary: { $backgroundColor: "blue", $color: "white" },
secondary: { $backgroundColor: "gray", $color: "black" },
};
return (
<Box
asChild
$padding="m"
$borderRadius={6}
$border="none"
$cursor="pointer"
{...variantStyles[variant]}
{...props}
>
<button>{children}</button>
</Box>
);
}
// Custom link component
function CustomLink({ children, ...props }) {
return (
<Box
asChild
$textDecoration="none"
$color="blue"
$padding="s"
$borderRadius={4}
$hover={{ $backgroundColor: "lightblue" }}
{...props}
>
<a>{children}</a>
</Box>
);
}
Event handlers are properly merged when using asChild
:
function InteractiveCard() {
const handleBoxClick = () => console.log("Box clicked");
const handleButtonClick = () => console.log("Button clicked");
return (
<Box
asChild
$padding="l"
$border="1px solid #ccc"
$borderRadius={8}
onClick={handleBoxClick} // This will be merged with button's onClick
>
<button onClick={handleButtonClick}>
{/* Both click handlers will fire */}
Click me!
</button>
</Box>
);
}
import { Box, useContainerWidth } from "@apvee/react-layout-kit";
function ResponsiveCard({ title, content, image }) {
const cardRef = React.useRef<HTMLDivElement>(null);
const width = useContainerWidth(cardRef);
// Adjust layout based on card width
const isCompact = width < 300;
return (
<Box
ref={cardRef}
$display="flex"
$flexDirection={{ xs: "column", md: isCompact ? "column" : "row" }}
$backgroundColor="white"
$borderRadius={12}
$boxShadow="0 4px 12px rgba(0,0,0,0.1)"
$overflow="hidden"
$maxWidth={600}
>
{/* Image */}
<Box
$width={{ xs: "100%", md: isCompact ? "100%" : "200px" }}
$height={{ xs: "200px", md: isCompact ? "150px" : "100%" }}
$backgroundColor="#f0f0f0"
$backgroundImage={`url(${image})`}
$backgroundSize="cover"
$backgroundPosition="center"
/>
{/* Content */}
<Box
$padding={{ xs: "m", sm: "l" }}
$display="flex"
$flexDirection="column"
$flex={1}
>
<Box
asChild
$fontSize={{ xs: 18, md: isCompact ? 16 : 20 }}
$fontWeight="600"
$marginBottom="s"
$color="#333"
>
<h3>{title}</h3>
</Box>
<Box
asChild
$fontSize={{ xs: 14, md: 16 }}
$color="#666"
$lineHeight={1.5}
>
<p>{content}</p>
</Box>
</Box>
</Box>
);
}
import { Container, Stack, SimpleGrid, Flex } from '@apvee/react-layout-kit';
// Container
function ResponsiveContainer({ children, ...props }) {
return (
<Container
size={{ xs: 320, md: 640, lg: 1200 }}
{...props}
>
{children}
</Container>
);
}
// Flexible Grid
function ResponsiveGrid({ columns = { xs: 1, sm: 2, md: 3, lg: 4 }, gap = 'md', children, ...props }) {
return (
<SimpleGrid
cols={columns}
spacing={gap}
{...props}
>
{children}
</SimpleGrid>
);
}
// Stack component
function VStack({ align, justify, gap = 'md', children, ...props }) {
return (
<Stack
align={align}
justify={justify}
gap={gap}
{...props}
>
{children}
</Stack>
);
}
// Usage
# Usage
function App() {
return (
<Container>
<Stack gap="xl">
<Box asChild $textAlign="center" $marginBottom="l">
<h1>My App</h1>
</Box>
<SimpleGrid cols={{ xs: 1, sm: 2, lg: 3 }} spacing="l">
<ResponsiveCard title="Card 1" content="Content 1" />
<ResponsiveCard title="Card 2" content="Content 2" />
<ResponsiveCard title="Card 3" content="Content 3" />
</SimpleGrid>
</Stack>
</Container>
);
}
import type {
// Core component types
BoxProps,
BaseBoxProps,
FlexProps,
FlexItemProps,
GridProps,
GridColProps,
StackProps,
SimpleGridProps,
AreaGridProps,
AreaGridItemProps,
ContainerProps,
CenterProps,
AspectRatioProps,
GroupProps,
SpaceProps,
// System types
ResponsiveValue,
BreakpointDefs,
SpacingValue,
BoxConfig,
// Advanced types
DollarCssProps,
IShortStyleBoxProps,
} from "@apvee/react-layout-kit";
import type { BoxProps } from "@apvee/react-layout-kit";
// Extend Box props
interface CustomCardProps extends BoxProps {
variant?: "primary" | "secondary" | "danger";
elevation?: "low" | "medium" | "high";
}
function CustomCard({
variant = "primary",
elevation = "medium",
children,
...boxProps
}: CustomCardProps) {
const variantStyles = {
primary: { $backgroundColor: "#007bff", $color: "white" },
secondary: { $backgroundColor: "#6c757d", $color: "white" },
danger: { $backgroundColor: "#dc3545", $color: "white" },
};
const elevationStyles = {
low: { $boxShadow: "0 1px 3px rgba(0,0,0,0.1)" },
medium: { $boxShadow: "0 4px 6px rgba(0,0,0,0.1)" },
high: { $boxShadow: "0 10px 25px rgba(0,0,0,0.15)" },
};
return (
<Box
$padding="l"
$borderRadius={8}
{...elevationStyles[elevation]}
{...variantStyles[variant]}
{...boxProps}
>
{children}
</Box>
);
}
import type { ResponsiveValue } from "@apvee/react-layout-kit";
// Helper function for responsive values
function createResponsiveValue<T>(
mobile: T,
tablet?: T,
desktop?: T
): ResponsiveValue<T> {
return {
xs: mobile,
...(tablet && { md: tablet }),
...(desktop && { lg: desktop }),
};
}
// Usage
const responsivePadding = createResponsiveValue(8, 16, 24);
const responsiveFontSize = createResponsiveValue("14px", "16px", "18px");
<Box $padding={responsivePadding} $fontSize={responsiveFontSize}>
Helper-created responsive values
</Box>;
- Debounced ResizeObserver: Measurements are debounced to 16ms (60fps) by default
- Memoized Computations: Responsive value resolution and class generation are memoized
- Efficient CSS: Uses Emotion for optimal CSS generation and caching
- Smart Re-renders: Only re-renders when props or container width actually change
// ✅ Good: Stable objects outside render
const cardStyles = {
$padding: { xs: "m", md: "l" },
$borderRadius: 8,
$backgroundColor: "white",
};
function MyComponent() {
return <Box {...cardStyles}>Content</Box>;
}
// ❌ Avoid: Creating objects in render
function MyComponent() {
return (
<Box
$padding={{ xs: "m", md: "l" }} // New object every render
$borderRadius={8}
$backgroundColor="white"
>
Content
</Box>
);
}
// ✅ Good: Use useMemo for complex computed styles
function MyComponent({ theme, size }) {
const dynamicStyles = React.useMemo(
() => ({
$backgroundColor: theme.primary,
$padding: size === "large" ? "xl" : "m",
$fontSize: {
xs: size === "large" ? 16 : 14,
md: size === "large" ? 20 : 16,
},
}),
[theme.primary, size]
);
return <Box {...dynamicStyles}>Content</Box>;
}
// Adjust debounce for different performance needs
const fastWidth = useContainerWidth(ref, { debounceMs: 8 }); // 120fps - very responsive
const normalWidth = useContainerWidth(ref, { debounceMs: 16 }); // 60fps - default
const slowWidth = useContainerWidth(ref, { debounceMs: 32 }); // 30fps - battery saving
The modular architecture enables excellent tree-shaking for optimal bundle sizes:
// ✅ Excellent: Import only what you need
import { Box } from "@apvee/react-layout-kit/components/Box";
import { Flex } from "@apvee/react-layout-kit/components/Flex";
// Bundle includes: Box + Flex (~2-3KB gzipped)
// ✅ Good: Barrel import (modern bundlers handle this well)
import { Box, Flex } from "@apvee/react-layout-kit";
// Bundle includes: Box + Flex + small barrel overhead
// ❌ Avoid: Deep imports (older pattern)
import Box from "@apvee/react-layout-kit/Box";
// Less reliable tree-shaking with some bundlers
Bundle Size Benefits:
- Granular imports: Include only components you use (~1-2KB per component)
- Automatic dead code elimination: Unused components are completely excluded
- Optimized dependencies: Shared utilities are deduplicated across components
- Framework-agnostic: Works with Webpack, Vite, Rollup, and other modern bundlers
The library is fully SSR-compatible with automatic fallbacks:
- Width measurement is disabled on server-side
- ResizeObserver usage is properly guarded
- No hydration mismatches with responsive styles
// For critical above-the-fold content, use useContainerWidth with fallback
function HeroSection() {
const containerRef = React.useRef<HTMLDivElement>(null);
const measuredWidth = useContainerWidth(containerRef);
// Use measured width, fallback to desktop width for SSR
const containerWidth = measuredWidth || 1200;
return (
<Box
ref={containerRef}
containerWidth={containerWidth}
$padding={{ xs: "m", md: "l", lg: "xl" }}
$fontSize={{ xs: 24, md: 32, lg: 40 }}
>
Critical hero content
</Box>
);
}
// For non-critical content, let it measure on client
function SidebarWidget() {
return (
<Box $padding={{ xs: "s", md: "m" }}>Non-critical sidebar content</Box>
);
}
// pages/_app.tsx
import { configureBox } from "@apvee/react-layout-kit";
// Configure once globally
configureBox({
breakpoints: {
xs: 0,
sm: 480,
md: 640,
lg: 1024,
xl: 1366,
xxl: 1920,
},
});
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />;
}
// Before (styled-components)
const StyledBox = styled.div`
display: flex;
padding: ${(props) => props.theme.spacing.medium};
@media (min-width: 768px) {
padding: ${(props) => props.theme.spacing.large};
}
`;
// After (@apvee/react-layout-kit)
<Box $display="flex" $padding={{ xs: "m", md: "l" }}>
Content
</Box>;
// Before (Chakra UI)
<Box p={[4, 6, 8]} bg="blue.500" color="white">
Content
</Box>
// After (@apvee/react-layout-kit)
<Box
p={{ xs: 'm', md: 'l', lg: 'xl' }}
$backgroundColor="blue"
$color="white"
>
Content
</Box>
- Modern browsers with ResizeObserver support
- React ≥ 17.0.0
- TypeScript ≥ 4.0 (recommended for best experience)
# Clone and install
git clone <repository-url>
cd react-box
npm install
# Start Storybook for development
npm run storybook
# Build library
npm run build
# Type checking
npm run check
# Build production bundle
npm run build
# Build Storybook documentation
npm run build-storybook
For comprehensive documentation including all features, advanced usage patterns, and implementation details, see llm-full.txt. This file contains the complete library reference and technical specifications designed to be used together with this README for AI code generation and development assistance.
MIT License - see LICENSE file for details.
@apvee/react-layout-kit - Build responsive, type-safe React applications with confidence! 🚀