TachUI Components Reference ​
Complete guide to TachUI's SwiftUI-inspired components with our specific syntax, modifiers, and patterns.
Important: While TachUI is inspired by SwiftUI, our syntax and patterns are specifically designed for web development. This guide covers TachUI's exact implementation - don't assume SwiftUI documentation applies directly.
Core Concepts ​
The Modifier System ​
Unlike SwiftUI, TachUI uses an explicit .modifier chain that must be terminated with .build():
// TachUI Pattern (Web-Specific)
Text("Hello")
.modifier
.fontSize(24)
.foregroundColor('#007AFF')
.padding(16)
.backgroundColor('white')
.cornerRadius(8)
.build() // Required to create component
// NOT SwiftUI - this won't work in TachUI:
Text("Hello")
.font(.title) // SwiftUI syntax
.foregroundColor(.blue)TachUI Modifier Pattern ​
TachUI uses a consistent modifier pattern that requires .modifier and .build():
// Correct TachUI pattern (all modifiers require this structure)
const component = Text("Hello")
.modifier
.fontSize(24)
.padding(16)
.foregroundColor('#007AFF')
.build()
// For complex styling (same pattern)
const styledComponent = Text("Hello")
.modifier
.fontSize(24)
.padding(16)
.foregroundColor('#007AFF')
.shadow({ x: 0, y: 2, radius: 4, color: 'rgba(0,0,0,0.1)' })
.backgroundColor('white')
.cornerRadius(8)
.build()Important: All TachUI modifiers must use the
.modifier.property().build()pattern. There are no "direct" modifiers.
Text Component ​
Display text content with full typography control.
Basic Usage ​
import { Text } from '@tachui/core'
// Static text
const greeting = Text("Hello, World!")
// Dynamic text with reactive content
const [message, setMessage] = createSignal("Dynamic content")
const dynamicText = Text(() => message())
// Styled text
const styledText = Text("Styled Text")
.modifier
.fontSize(24)
.fontWeight('bold')
.foregroundColor('#007AFF')
.backgroundColor('#f0f8ff')
.padding(16)
.cornerRadius(8)
.build()Typography Modifiers ​
Text("Typography Example")
.modifier
.fontSize(24) // Number in pixels
.fontWeight('bold') // CSS font-weight values
.fontFamily('Arial, sans-serif') // CSS font-family
.lineHeight(1.5) // Number (multiplier) or string
.letterSpacing(0.5) // Number in pixels
.textAlign('center') // 'left' | 'center' | 'right' | 'justify'
.textDecoration('underline') // CSS text-decoration
.textTransform('uppercase') // CSS text-transform
.build()Advanced Text Features ​
// Multiline text with line limits
Text("Very long text that might need truncation...")
.modifier
.lineLimit(2) // Limit to 2 lines
.textOverflow('ellipsis') // Handle overflow
.build()
// Selectable text
Text("This text can be selected")
.modifier
.userSelect('text') // Enable text selection
.build()
// Interactive text
Text("Clickable Text")
.modifier
.onTap(() => console.log('Text clicked'))
.cursor('pointer')
.textDecoration('underline')
.build()Button Component ​
Interactive button with press states and haptic feedback.
Basic Usage ​
import { Button } from '@tachui/core'
// Simple button
const basicButton = Button('Click Me', () => {
console.log('Button clicked!')
})
// Styled button
const styledButton = Button('Save', async () => {
await saveData()
})
.modifier
.backgroundColor('#007AFF')
.foregroundColor('white')
.padding(12, 20) // vertical, horizontal
.cornerRadius(8)
.fontSize(16)
.fontWeight('600')
.build()Button States ​
const [isLoading, setIsLoading] = createSignal(false)
const [isDisabled, setIsDisabled] = createSignal(false)
Button('Submit', async () => {
setIsLoading(true)
await submitForm()
setIsLoading(false)
})
.modifier
.disabled(() => isLoading() || isDisabled())
.opacity(() => isDisabled() ? 0.5 : 1.0)
.cursor(() => isDisabled() ? 'not-allowed' : 'pointer')
.build()Button Variants ​
// Primary button
Button('Primary', action)
.modifier
.backgroundColor('#007AFF')
.foregroundColor('white')
.build()
// Secondary button
Button('Secondary', action)
.modifier
.backgroundColor('transparent')
.foregroundColor('#007AFF')
.border(1, '#007AFF')
.build()
// Destructive button
Button('Delete', action)
.modifier
.backgroundColor('#ff3b30')
.foregroundColor('white')
.build()
// Text button
Button('Cancel', action)
.modifier
.backgroundColor('transparent')
.foregroundColor('#666')
.build()TextField Component ​
Text input with validation and reactive updates.
Basic Usage ​
import { TextField } from '@tachui/core'
const [text, setText] = createSignal('')
// Basic text field
TextField({
value: text(),
onChange: setText,
placeholder: 'Enter text...'
})
.modifier
.padding(12)
.border(1, '#e0e0e0')
.cornerRadius(6)
.fontSize(16)
.build()Input Types ​
// Email input
TextField({
type: 'email',
value: email(),
onChange: setEmail,
placeholder: 'Enter email'
})
// Password input
TextField({
type: 'password',
value: password(),
onChange: setPassword
})
// Number input
TextField({
type: 'number',
value: count().toString(),
onChange: (val) => setCount(parseInt(val))
})
// Multiline text area
TextField({
multiline: true,
rows: 4,
value: comment(),
onChange: setComment
})TextField Validation ​
const [email, setEmail] = createSignal('')
const [error, setError] = createSignal('')
TextField({
type: 'email',
value: email(),
onChange: (value) => {
setEmail(value)
// Validate email
if (!value.includes('@')) {
setError('Please enter a valid email')
} else {
setError('')
}
},
placeholder: 'Enter email'
})
.modifier
.borderColor(() => error() ? '#ff3b30' : '#e0e0e0')
.build()
// Show error message
if (error()) {
Text(error())
.modifier
.foregroundColor('#ff3b30')
.fontSize(14)
.build()
}Image Component ​
Display images with loading states and content modes.
Basic Usage ​
import { Image } from '@tachui/core'
// Simple image
Image({ src: '/path/to/image.jpg', alt: 'Description' })
.modifier
.frame({ width: 300, height: 200 })
.cornerRadius(8)
.build()
// Responsive image
Image({ src: '/hero-image.jpg' })
.modifier
.frame({ width: '100%', height: 'auto' })
.maxWidth(800)
.build()Content Modes ​
// Aspect fit (like SwiftUI .scaleAspectFit)
Image({ src: '/photo.jpg' })
.modifier
.frame({ width: 300, height: 200 })
.objectFit('contain') // CSS object-fit: contain
.build()
// Aspect fill (like SwiftUI .scaleAspectFill)
Image({ src: '/photo.jpg' })
.modifier
.frame({ width: 300, height: 200 })
.objectFit('cover') // CSS object-fit: cover
.build()
// Center (no scaling)
Image({ src: '/icon.png' })
.modifier
.frame({ width: 100, height: 100 })
.objectFit('none')
.objectPosition('center')
.build()Loading States ​
const [loadingState, setLoadingState] = createSignal<'loading' | 'loaded' | 'error'>('loading')
Image({
src: '/large-image.jpg',
onLoad: () => setLoadingState('loaded'),
onError: () => setLoadingState('error')
})
.modifier
.opacity(() => loadingState() === 'loaded' ? 1 : 0.5)
.build()
// Show loading indicator
if (loadingState() === 'loading') {
Text('Loading...')
.modifier
.fontSize(14)
.foregroundColor('#666')
.build()
}Layout Components ​
VStack - Vertical Layout ​
Stack components vertically with spacing and alignment.
import { VStack } from '@tachui/core'
VStack({
children: [
Text('First Item'),
Text('Second Item'),
Button('Action', () => {})
],
spacing: 16, // Space between items (pixels)
alignment: 'leading' // 'leading' | 'center' | 'trailing'
})
.modifier
.padding(20)
.backgroundColor('#f8f9fa')
.cornerRadius(8)
.build()HStack - Horizontal Layout ​
Stack components horizontally.
HStack({
children: [
Text('Left'),
Text('Center').modifier.flexGrow(1).build(), // Take remaining space
Text('Right')
],
spacing: 12,
alignment: 'center' // 'top' | 'center' | 'bottom'
})
.modifier
.padding(16)
.build()ZStack - Layered Layout ​
Layer components on top of each other.
ZStack({
children: [
// Background layer
Text('')
.modifier
.backgroundColor('#007AFF')
.frame({ width: 200, height: 100 })
.cornerRadius(8)
.build(),
// Foreground content
Text('Overlay Text')
.modifier
.foregroundColor('white')
.fontWeight('bold')
.build()
],
alignment: 'center' // Position of overlay content
})Form Components ​
Form Container ​
Groups form elements with consistent styling.
import { Form, Section } from '@tachui/core'
Form({
onSubmit: handleSubmit,
children: [
Section({
title: 'Personal Information',
children: [
TextField({ placeholder: 'Name', value: name(), onChange: setName }),
TextField({ placeholder: 'Email', value: email(), onChange: setEmail })
]
})
]
})
.modifier
.padding(20)
.backgroundColor('#f8f9fa')
.build()Toggle Switch ​
Boolean input with switch styling.
import { Toggle } from '@tachui/core'
const [isEnabled, setIsEnabled] = createSignal(false)
Toggle({
value: isEnabled(),
onChange: setIsEnabled,
label: 'Enable Notifications'
})
.modifier
.accentColor('#007AFF') // Switch color when enabled
.build()Slider Component ​
Numeric input with slider interface.
import { Slider } from '@tachui/advanced-forms'
const [volume, setVolume] = createSignal(50)
Slider({
value: volume(),
onChange: setVolume,
min: 0,
max: 100,
step: 1
})
.modifier
.accentColor('#007AFF')
.frame({ width: 300 })
.build()
// Display current value
Text(() => `Volume: ${volume()}%`)Picker Component ​
Selection input with multiple styles.
import { Picker } from '@tachui/core'
const [selectedColor, setSelectedColor] = createSignal('red')
const colors = ['red', 'green', 'blue', 'yellow']
// Dropdown picker
Picker({
selection: selectedColor(),
onChange: setSelectedColor,
options: colors.map(color => ({ value: color, label: color }))
})
// Segmented picker (like iOS segmented control)
Picker({
selection: selectedColor(),
onChange: setSelectedColor,
options: colors.map(color => ({ value: color, label: color })),
style: 'segmented'
})
.modifier
.frame({ width: 300 })
.build()Common Modifiers Reference ​
Layout Modifiers ​
component
.frame({ width: 300, height: 200 }) // Set dimensions
.padding(16) // All sides
.padding(16, 20) // vertical, horizontal
.padding({ top: 10, right: 15, bottom: 10, left: 15 })
.margin(12) // External spacing
.position('relative') // CSS position
.zIndex(10) // Stack orderAppearance Modifiers ​
component
.backgroundColor('#f8f9fa') // Background color
.foregroundColor('#333') // Text/content color
.opacity(0.8) // Transparency (0-1)
.cornerRadius(8) // Border radius
.border(1, '#e0e0e0') // Border width, color
.shadow({ x: 0, y: 2, radius: 4, color: 'rgba(0,0,0,0.1)' })Animation Modifiers ​
component
.transition('all', 200, 'ease-out') // Property, duration, easing
.animation('fadeIn', 300) // Named animation
.transform('scale(1.05)') // CSS transformInteraction Modifiers ​
component
.onTap(() => console.log('Tapped')) // Click handler
.onHover((hovered) => console.log(hovered)) // Hover state
.cursor('pointer') // Mouse cursor
.disabled(false) // Enable/disable interactionKey Differences from SwiftUI ​
1. Explicit Modifier Chains ​
- SwiftUI: Modifiers can be chained directly
- TachUI: Complex styling requires
.modifier.build()pattern
2. Web-Specific Values ​
- Colors: Use CSS color values (
'#007AFF','rgb(0,122,255)') not SwiftUI colors - Dimensions: Numbers are pixels, strings for CSS units (
'100%','50vh') - Fonts: CSS font-family strings, not SwiftUI font names
3. Event Handling ​
- SwiftUI: Uses action parameters
- TachUI: Uses explicit event modifiers (
.onTap(),.onHover())
4. Reactive Values ​
- SwiftUI: Uses
@Stateproperty wrappers - TachUI: Uses signal functions in modifiers (
() => signal())
Best Practices ​
1. Use TypeScript ​
Always import components with full type safety:
import { Text, Button, VStack } from '@tachui/core'
// Not: import * as TachUI from '@tachui/core'2. Use Consistent Modifier Pattern ​
Always use the .modifier.build() pattern for TachUI components:
// Correct TachUI pattern
Text('Hello')
.modifier
.fontSize(24)
.padding(16)
.build()
// This syntax doesn't exist in TachUI
// Text('Hello').fontSize(24).padding(16)3. Reactive Styling ​
Use signals for dynamic values:
const [isDark, setIsDark] = createSignal(false)
Text('Themed Text')
.modifier
.foregroundColor(() => isDark() ? 'white' : 'black')
.backgroundColor(() => isDark() ? '#333' : 'white')
.build()4. Semantic Component Names ​
Create meaningful component names that express intent:
function PrimaryButton(title: string, action: () => void) {
return Button(title, action)
.modifier
.backgroundColor('#007AFF')
.foregroundColor('white')
.padding(12, 20)
.cornerRadius(8)
.build()
}This comprehensive guide covers TachUI's specific implementation. While inspired by SwiftUI, always refer to this documentation for accurate TachUI syntax and patterns.