@noiir/core
v2.2.2
Published
A comprehensive React component library and design system with Figma integration, featuring customizable components, variants, and theming capabilities
Maintainers
Readme
Noiir
A React component framework that mirrors Figma design properties with Frame-based components. Build UIs with the same flexibility and control as Figma, directly in React.
Features
✨ Frame-Based Components - Every component built on Figma's Frame concept
🎨 Complete Design Properties - Position, auto layout, fill, stroke, effects, typography
🎯 Type-Safe - Full TypeScript support with exported types
📦 Tree-Shakeable - Multiple entry points for optimal bundle size
🎪 Variant System - Pre-built and customizable component variants
🌈 Theme Support - Comprehensive color and typography system
🎭 Animation System - Built-in state-based animations and transitions
🖼️ Mask & Group - Advanced clipping and organizational components
Installation
npm install @noiir/coreQuick Start
import { Frame, Button, Group, Mask } from '@noiir/core';
function App() {
return (
<Frame
autoLayout={{ flow: 'vertical', gap: 16, padding: 24 }}
fill={{ type: 'solid', color: 'primary3' }}
appearance={{ cornerRadius: 12 }}
>
<Group animate={{ hover: 'scale-105' }}>
<Button variant="primary">Click me</Button>
</Group>
<Mask appearance={{ cornerRadius: 8 }}>
<Frame fill={{ type: 'image', image: { src: '/hero.jpg', scaleMode: 'cover' } }} />
</Mask>
</Frame>
);
}Project Structure
Noiir follows a modular architecture with clear separation of concerns:
📁 __frame-core__/
Core frame properties and utilities that power all components:
- animate/ - Animation and transition properties
- appearance/ - Fill, stroke, cursor, and visual styling
- layout/ - Auto-layout, flex properties, spacing, sizing
- position/ - Absolute/relative positioning, z-index
- typography/ - Font styles, sizes, weights, text properties
- effects/ - Shadows, blur, opacity, filters
- events/ - Event handlers and interactions
- utils/ - CSS units, utilities, and helpers
- variants/ - Size props and variant system
📁 __components__/
All React components organized by atomic design principles:
- atoms/ - Basic UI elements (Button, Input, Badge, etc.)
- molecules/ - Composite components (Card, Dropdown, Dialog, etc.)
- organisms/ - Complex components (Navbar, etc.)
- frame/ - Core Frame component
- group/ - Group component for animation organization
- mask/ - Mask component for clipping functionality
📁 __variants__/
Variant definitions, theme system, and design tokens:
- atoms/ - Component-specific variants
- molecules/ - Composite component variants
- theme/ - Colors, fonts, icons, and theme utilities
- index.ts - Centralized variant exports
📁 __stories__/
Storybook stories for all components (development only, not published)
📁 docs/
Comprehensive documentation and guides
Package Exports
Noiir provides multiple entry points for flexibility and optimal bundle sizes:
Main Export (Everything)
import { Frame, Button, Input, Group, Mask, colors, buttonVariants } from '@noiir/core';Frame & Core Properties
import {
Frame,
PositionProps,
AutoLayoutProps,
FillProps,
AnimateProps,
EffectsProps
} from '@noiir/core/frame-core';Components Only
import { Button, Input, Card, Dropdown, Group, Mask } from '@noiir/core/components';Individual Components
import { Button } from '@noiir/core/components/Button';
import { Group } from '@noiir/core/components/Group';
import { Mask } from '@noiir/core/components/Mask';Variants & Theme
import { buttonVariants, inputVariants } from '@noiir/core/variants';
import { colors, typography, resolveColor } from '@noiir/core/theme';Frame-Core Only
import {
ExtendVariant,
LayoutProps,
FillProps,
TypographyProps
} from '@noiir/core/frame-core';Development Workflow
Project Structure Overview
noiir/
├── __frame-core__/ # Core properties and utilities
├── __components__/ # React components (atoms/molecules/organisms)
├── __variants__/ # Variants, themes, and design tokens
├── __stories__/ # Storybook stories (dev only)
├── docs/ # Documentation
├── dist/ # Build output (published)
├── package.json
├── tsconfig.json
├── vite.config.ts
└── README.mdBuilding from Source
# Install dependencies
npm install
# Development with watch mode
npm run dev
# Build the package
npm run build
# Run Storybook
npm run storybook
# Build Storybook
npm run build-storybookArchitecture Principles
Noiir follows atomic design principles with a layered architecture:
- Frame Props → Foundational design properties
- Frame Component → Core building block
- Components → Specific UI elements
- Variants → Style configurations
All components extend the base Frame component, ensuring consistency and enabling unlimited customization through Frame properties.
Core Concepts
Frame Component
The Frame component is the foundation of Noiir. It mirrors Figma's frame properties:
<Frame
// Position
position={{ x: 100, y: 50, type: 'absolute' }}
// Auto Layout
autoLayout={{
flow: 'horizontal',
gap: 16,
padding: 24,
alignment: 'center',
distribution: 'space-between'
}}
// Fill
fill={{
type: 'linear-gradient',
angle: 45,
stops: [
{ color: 'primary3', position: 0 },
{ color: 'primary8', position: 1 }
]
}}
// Stroke
stroke={{
type: 'solid',
color: 'neutral6',
weight: 2,
position: 'inside'
}}
// Appearance
appearance={{
cornerRadius: 12,
opacity: 0.95
}}
// Effects
effects={{
type: 'drop-shadow',
color: 'rgba(0,0,0,0.1)',
offsetX: 0,
offsetY: 4,
blur: 8
}}
// Typography (for text frames)
typography={{
fontSize: 16,
fontWeight: 600,
textAlign: 'center'
}}
>
{/* Your content */}
</Frame>Group Component
The Group component is a pure container for organizational and animation purposes. It doesn't render any DOM elements but provides hierarchical targeting for animations:
import { Group, Button } from '@noiir/core';
// Group multiple elements for coordinated animations
<Group animate={{ hover: 'scale-105', click: 'scale-95' }}>
<Button variant="primary">Button 1</Button>
<Button variant="secondary">Button 2</Button>
</Group>
// Nested groups for complex hierarchies
<Group animate={{ hover: 'fade-in' }}>
<Group animate={{ click: 'bounce' }}>
<Button>Animated Button</Button>
</Group>
</Group>Mask Component
The Mask component provides advanced clipping functionality with rectangular and SVG path support:
import { Mask, Frame } from '@noiir/core';
// Rectangular mask with rounded corners
<Mask appearance={{ cornerRadius: 16 }}>
<Frame fill={{ type: 'image', image: { src: '/photo.jpg', scaleMode: 'cover' } }} />
</Mask>
// SVG path mask
<Mask mask={{
type: 'path',
path: 'M50,0 L100,50 L50,100 L0,50 Z' // Diamond shape
}}>
<Frame fill={{ type: 'solid', color: 'primary5' }} />
</Mask>Fill Types
// Solid color
<Frame fill={{ type: 'solid', color: 'primary5' }} />
// Linear gradient
<Frame fill={{
type: 'linear-gradient',
angle: 90,
stops: [
{ color: '#ff0000', position: 0 },
{ color: '#0000ff', position: 1 }
]
}} />
// Radial gradient
<Frame fill={{
type: 'radial-gradient',
stops: [
{ color: 'primary3', position: 0 },
{ color: 'primary8', position: 1 }
]
}} />
// Image fill
<Frame fill={{
type: 'image',
image: {
src: '/path/to/image.jpg',
scaleMode: 'fill' // 'fill' | 'fit' | 'crop' | 'tile'
}
}} />Theme System
Noiir includes a comprehensive theme system:
import { colors, typography } from 'noiir/theme';
// Use theme colors
<Frame fill={{ color: colors.primary5 }} />
// Or use shorthand
<Frame fill={{ color: 'primary5' }} />
// Typography presets
<Frame typography={typography.heading1} />Components
All components are built on Frame and support variants:
import { Button, Input, Card, Dropdown, Group, Mask } from '@noiir/core';
// Atoms
<Button variant="primary">Click me</Button>
<Input variant="outlined" placeholder="Enter text" />
<Toggle variant="default" />
<Slider variant="primary" min={0} max={100} />
<Checkbox variant="default" />
<Avatar variant="circle" src="/avatar.jpg" />
<Badge variant="primary">New</Badge>
// Molecules
<Card variant="elevated">
<h2>Card Title</h2>
<p>Card content</p>
</Card>
<Dropdown variant="default" options={options} />
<Dialog variant="centered">Dialog content</Dialog>
// Layout & Effects
<Group animate={{ hover: 'scale-105' }}>
<Button>Grouped Button</Button>
</Group>
<Mask appearance={{ cornerRadius: 8 }}>
<Frame fill={{ type: 'image', image: { src: '/image.jpg' } }} />
</Mask>Custom Variants
Create your own variants:
import { buttonVariants } from 'noiir/variants';
const customButton = {
...buttonVariants.primary,
baseStyle: {
...buttonVariants.primary.baseStyle,
fill: { type: 'solid', color: 'accent5' }
}
};
<Button variant={customButton}>Custom</Button>TypeScript Support
Noiir is fully typed. Import types for your props:
import type {
FrameProps,
FillProps,
AutoLayoutProps
} from 'noiir/frame';
interface MyComponentProps {
layout: AutoLayoutProps;
fill: FillProps;
}Storybook
View all components in Storybook:
npm run storybookBuild
Build the package:
npm run buildLicense & Commercial Use
Noiir is open source under the MIT License. Copyright (c) 2025 Andrew Sterns. All rights reserved.
Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
# Clone the repository
git clone https://github.com/andrewsterns/noiir.git
cd noiir
# Install dependencies
npm install
# Start development
npm run dev
# Run tests
npm test
# Build and test
npm run buildSupport
- Documentation: See
docs/folder for detailed guides - Storybook:
npm run storybookfor interactive component docs - Issues: GitHub Issues
- Discussions: GitHub Discussions
Changelog
See CHANGELOG.md for version history and updates.
Built with ❤️ using React, TypeScript, and Figma design principles.
