@tachui/primitives
v0.12.1
Published
Basic UI components for tachUI framework
Maintainers
Readme
@tachui/primitives
Foundation UI components for tachUI applications - the building blocks of modern web interfaces.
Overview
The @tachui/primitives package provides essential UI components that serve as the foundation for all tachUI applications. These components offer SwiftUI-inspired APIs with web-native performance and accessibility.
Installation
npm install @tachui/primitives
# or
pnpm add @tachui/primitivesCore Components
Layout Components
VStack
Vertically stacks child components with customizable spacing and alignment.
import { VStack, Text } from '@tachui/primitives'
VStack({
spacing: 16,
alignment: 'leading',
children: [Text('First Item'), Text('Second Item'), Text('Third Item')],
})HStack
Horizontally arranges child components with flexible alignment options.
import { HStack, Button } from '@tachui/primitives'
HStack({
spacing: 12,
alignment: 'center',
children: [Button('Cancel'), Spacer(), Button('Save')],
})ZStack
Overlays components on top of each other with alignment control.
import { ZStack, Image, Text } from '@tachui/primitives'
ZStack({
alignment: 'bottomTrailing',
children: [
Image('/hero-background.jpg'),
Text('Overlay Text')
.padding(16)
.backgroundColor('rgba(0,0,0,0.7)')
.foregroundColor('white')
,
],
})Spacer
Flexible space that expands to fill available space in stacks.
HStack({
children: [
Text('Left'),
Spacer(), // Pushes content to edges
Text('Right'),
],
})Divider
Visual separator line with customizable appearance.
VStack({
children: [Text('Section 1'), Divider(), Text('Section 2')],
})Shapes
Circle, Rectangle, RoundedRectangle, Ellipse and Capsule fill their
frame and are styled with .fill(), .stroke(), .strokeBorder(),
.inset(), .trim() and .strokeStyle(), which chain with modifiers in
either order.
| Shape | Geometry |
| --- | --- |
| Circle() | Inscribed in the short side of its frame, centered |
| Rectangle() | The frame itself, square corners |
| RoundedRectangle(cornerRadius) | Circular corners, clamped to half the short side |
| Ellipse() | Fills the frame, one radius per axis |
| Capsule() | Semicircular caps on the short axis, either orientation |
Circle().fill('#007AFF').frame({ width: 12, height: 12 })
RoundedRectangle(12).strokeBorder('#E5E5EA', 1)
RoundedRectangle({ cornerRadius: 12 }).fill('#F2F2F7')
Capsule().fill('#007AFF').frame({ width: 64, height: 24 })
Image(source)
.frame({ width: 40, height: 40 })
.clipShape('circle')
.overlay(Circle().inset(1).stroke('#007AFF', 2)) // a ring 1px inside the edge.trim(from, to) draws part of the path, for progress rings and spinners:
Circle()
.trim(0, progress)
.strokeStyle({ lineWidth: 4, lineCap: 'round' })
.stroke('#007AFF')
.transform('rotate(-90deg)') // the path starts at three o'clock, as in SwiftUI.trim() strokes; it does not shorten the path. SVG ignores a dash pattern
when filling, so a trimmed shape still fills — and clips — as the whole shape.
Trim and strokeStyle's dash are exclusive — both use stroke-dasharray,
so a shape carrying both draws the trim and warns once.
RoundedRectangle's radius is clamped to half the short side, as in SwiftUI, so
an over-large radius draws a capsule instead of distorting into elliptical
corners.
.inset() and .strokeBorder() leave that radius alone, so subtract from it
yourself where you want corners concentric with the host:
RoundedRectangle(12).strokeBorder(tint, 4) has an outer stroke edge of radius
14, two pixels proud of a cornerRadius: 12 host, while
RoundedRectangle(10).strokeBorder(tint, 4) lands flush. Capsule and Circle
recompute their curvature from the inset rect and need no such help. Ellipse
stays inside its frame but is not flush with an elliptical host: the parallel
curve of an ellipse is not an ellipse, so the border bulges between the axis
extremes.
Display Components
Text
Displays text content with full typography control.
Text('Hello, tachUI!')
.font({ family: 'San Francisco', size: 18, weight: 600 })
.foregroundColor('#007AFF')
.textAlign('center')
Advanced Text Features:
// Multiline text with line clamping
Text(longContent).lineClamp(3).wordBreak('break-word')
// Reactive text content
const [count, setCount] = createSignal(0)
Text(() => `Count: ${count()}`)Image
Displays images with loading states and aspect ratio control.
Image('/path/to/image.jpg')
.size({ width: 200, height: 150 })
.cornerRadius(8)
.aspectRatio('cover')
Image with Assets:
import { Assets } from '@tachui/core'
Image(Assets.profilePicture)
.size({ width: 60, height: 60 })
.cornerRadius(30)
HTML
Renders raw HTML content safely with sanitization.
HTML({
content: '<p>Safe <strong>HTML</strong> content</p>',
sanitize: true,
})Control Components
Button
Interactive button component with full customization support.
Button('Click Me', () => {
console.log('Button clicked!')
})
.padding({ horizontal: 16, vertical: 8 })
.backgroundColor('#007AFF')
.foregroundColor('white')
.cornerRadius(8)
Button States:
Button('Stateful Button', handleClick)
.backgroundColor('#007AFF')
.hover({ backgroundColor: '#0051D5' })
.active({ transform: 'scale(0.95)' })
.disabled({ opacity: 0.5 })
Toggle
Switch/toggle component for boolean states.
const [isEnabled, setIsEnabled] = createSignal(false)
Toggle({
isOn: () => isEnabled(),
onToggle: setIsEnabled,
})
.accentColor('#007AFF')
Picker
Selection component for choosing from multiple options.
const options = ['Option 1', 'Option 2', 'Option 3']
const [selected, setSelected] = createSignal(options[0])
Picker({
selection: () => selected(),
onSelectionChange: setSelected,
options: options,
renderOption: option => Text(option),
})Form Components
BasicInput
Text input component with validation and formatting support.
const [text, setText] = createSignal('')
BasicInput({
value: () => text(),
onInput: setText,
placeholder: 'Enter your name',
})
.padding(12)
.border(1, '#E5E5EA')
.cornerRadius(8)
Advanced Input Features:
BasicInput({
value: () => email(),
onInput: setEmail,
type: 'email',
validation: value => value.includes('@'),
errorMessage: 'Please enter a valid email',
})BasicForm
Simple form container with validation and submission handling.
BasicForm({
onSubmit: data => {
console.log('Form submitted:', data)
},
children: [
BasicInput({ name: 'username', placeholder: 'Username' }),
BasicInput({ name: 'email', type: 'email', placeholder: 'Email' }),
Button('Submit', null), // null indicates form submission
],
})Usage Patterns
Building Complex Layouts
VStack({
spacing: 20,
children: [
// Header
HStack({
alignment: 'center',
children: [
Image(Assets.logo).size({ width: 40, height: 40 }),
Text('My App').font({ size: 24, weight: 'bold' }),
Spacer(),
Button('Menu', toggleMenu),
],
}),
// Content
VStack({
spacing: 16,
children: [
Text('Welcome to tachUI!')
.font({ size: 18 })
.textAlign('center')
,
Divider(),
HStack({
spacing: 12,
children: [
Button('Get Started', startOnboarding),
Button('Learn More', openDocs)
.backgroundColor('transparent')
.foregroundColor('#007AFF')
,
],
}),
],
}),
],
})Responsive Design
VStack({
children: items.map(item =>
HStack({
spacing: { mobile: 8, desktop: 16 },
children: [
Image(item.image)
.size({ mobile: 40, desktop: 60 })
.cornerRadius({ mobile: 4, desktop: 8 })
,
VStack({
alignment: 'leading',
children: [
Text(item.title)
.font({ size: { mobile: 16, desktop: 18 } })
,
Text(item.description)
.font({ size: { mobile: 14, desktop: 16 } })
.opacity(0.7)
,
],
}),
],
})
),
})Accessibility Features
All primitive components include comprehensive accessibility support:
- ARIA Labels: Automatic and customizable ARIA attributes
- Keyboard Navigation: Full keyboard support for interactive elements
- Screen Reader Support: Optimized for screen reader compatibility
- Focus Management: Proper focus handling and visual indicators
- High Contrast: Support for high contrast modes
Button('Accessible Button', handleClick)
.accessibilityLabel('Save document')
.accessibilityRole('button')
.accessibilityHint('Saves the current document')
Styling Integration
Primitives work seamlessly with the modifier system:
import { padding, margin, backgroundColor } from '@tachui/modifiers'
Text('Styled with modifiers')
.apply(padding(16))
.apply(margin({ vertical: 8 }))
.apply(backgroundColor('#F2F2F7'))
Performance Characteristics
- Minimal Bundle Size: Tree-shakeable components
- Efficient Rendering: Fine-grained reactivity with minimal re-renders
- Memory Efficient: Automatic cleanup and memory management
- GPU Accelerated: CSS transforms and animations when possible
Component Validation
Built-in validation ensures proper component usage:
// Development warnings for common mistakes
VStack({
children: 'String', // ❌ Warning: children should be array
})
// Type-safe props
Text(123) // ❌ TypeScript error: content must be string or signalIntegration with Other Packages
With Flow Control
import { Show, ForEach } from '@tachui/flow-control'
VStack({
children: [
Show({
when: () => isLoading(),
children: Text('Loading...'),
}),
ForEach({
data: () => items(),
renderItem: item =>
HStack({
children: [
Text(item.name),
Spacer(),
Button('Edit', () => editItem(item)),
],
}),
}),
],
})With Navigation
import { NavigationLink } from '@tachui/navigation'
VStack({
children: [
NavigationLink({
destination: '/profile',
children: HStack({
children: [
Image(userAvatar),
Text(userName),
Spacer(),
Text('>').opacity(0.5),
],
}),
}),
],
})Best Practices
- Use Semantic Components: Choose components based on meaning, not appearance
- Leverage the Stack System: Use VStack, HStack, and ZStack for layouts instead of CSS
- Apply Modifiers Consistently: Use the modifier chain for all styling
- Consider Accessibility: Always provide appropriate labels and roles
- Optimize for Performance: Use signals for reactive content, avoid object creation in renders
Browser Support
- Modern browsers (Chrome 88+, Firefox 85+, Safari 14+, Edge 88+)
- Progressive enhancement for older browsers
- Graceful fallback for unsupported features
License
This package is part of the tachUI framework and is licensed under the MPL-2.0 License.
