Text Component
The Text component is one of TachUI's most fundamental components, providing comprehensive typography support with reactive content, extensive styling options, and built-in accessibility features.
Overview
The Text component displays text content with full support for:
- Reactive content updates
- Typography presets following design system patterns
- Advanced text formatting and styling
- Accessibility features
- Interactive capabilities
Basic Usage
Simple Text
import { Text } from '@tachui/core'
// Static text
Text("Hello, World!")
.modifier
.build()Reactive Text
import { Text, createSignal } from '@tachui/core'
const [message, setMessage] = createSignal("Initial message")
// Reactive text that updates automatically
Text(message)
.modifier
.foregroundColor('#333')
.build()
// Update the text
setMessage("Updated message!")Functional Text
const currentTime = () => new Date().toLocaleTimeString()
Text(currentTime)
.modifier
.font({ family: 'monospace', size: 16 })
.build()Typography Presets
TachUI provides built-in typography presets that follow system design patterns:
import { TextStyles } from '@tachui/core'
// Large title
TextStyles.LargeTitle("Welcome")
.modifier
.foregroundColor('#000')
.build()
// Regular title
TextStyles.Title("Section Title")
.modifier
.build()
// Body text
TextStyles.Body("This is body text with proper line height and sizing.")
.modifier
.build()
// Caption text
TextStyles.Caption("Small caption text")
.modifier
.opacity(0.7)
.build()Available Typography Presets
| Preset | Size | Weight | Line Height | Use Case |
|---|---|---|---|---|
LargeTitle | 34px | 400 | 1.2 | Main page titles |
Title | 28px | 400 | 1.3 | Section headers |
Title2 | 22px | 400 | 1.3 | Sub-section headers |
Title3 | 20px | 400 | 1.4 | Minor headers |
Headline | 17px | 600 | 1.4 | Emphasized text |
Body | 17px | 400 | 1.5 | Main content |
Callout | 16px | 400 | 1.4 | Highlighted content |
Subheadline | 15px | 400 | 1.4 | Secondary content |
Footnote | 13px | 400 | 1.3 | Footnotes |
Caption | 12px | 400 | 1.2 | Image captions |
Caption2 | 11px | 400 | 1.1 | Fine print |
Text Formatting
Using TextFormat Utilities
import { TextFormat } from '@tachui/core'
// Bold text
TextFormat.bold("Important message")
.modifier
.build()
// Italic text
TextFormat.italic("Emphasized text")
.modifier
.build()
// Underlined text
TextFormat.underline("Underlined text")
.modifier
.build()
// Monospace text
TextFormat.monospace("code snippet")
.modifier
.backgroundColor('#f5f5f5')
.padding(4)
.build()
// Multiple formatting options
TextFormat.formatted("Multi-formatted text", {
bold: true,
italic: true,
underline: true
})
.modifier
.build()Manual Font Styling
Text("Custom styled text")
.modifier
.font({
family: 'Georgia, serif',
size: 18,
weight: '600',
style: 'italic',
variant: 'small-caps'
})
.build()Advanced Text Properties
Text Alignment and Decoration
Text("Centered text")
.modifier
.textAlign('center')
.textDecoration('underline')
.textTransform('uppercase')
.build()Line Spacing and Letter Spacing
Text("Spaced text with custom typography")
.modifier
.lineHeight(1.8)
.letterSpacing('2px')
.wordSpacing('4px')
.build()Line Limiting and Truncation
// Limit to 3 lines with tail truncation
Text("This is a very long text that will be truncated after three lines...")
.modifier
.frame({ width: 200 })
.lineHeight(1.4)
.css({
display: '-webkit-box',
'-webkit-line-clamp': '3',
'-webkit-box-orient': 'vertical',
overflow: 'hidden',
textOverflow: 'ellipsis'
})
.build()Accessibility
Semantic Roles
// Heading text
Text("Page Title")
.modifier
.accessibilityRole('heading')
.accessibilityLevel(1)
.font(Typography.largeTitle)
.build()
// Label text
Text("Username:")
.modifier
.accessibilityRole('label')
.build()Accessibility Labels
Text("👍")
.modifier
.accessibilityLabel("Thumbs up emoji")
.build()Interactive Text
Clickable Text
const handleClick = () => {
console.log('Text clicked!')
}
Text("Click me")
.modifier
.foregroundColor('#007AFF')
.textDecoration('underline')
.cursor('pointer')
.onTap(handleClick)
.build()Long Press Support
const handleLongPress = () => {
console.log('Long press detected')
}
Text("Long press me")
.modifier
.onLongPress(handleLongPress)
.build()Responsive Typography
Responsive Font Sizes
import { createSignal } from '@tachui/core'
const [isMobile, setIsMobile] = createSignal(window.innerWidth < 768)
Text("Responsive text")
.modifier
.font({
size: () => isMobile() ? 16 : 20,
weight: '400'
})
.build()Responsive Line Height
Text("Text with responsive line height")
.modifier
.lineHeight(() => isMobile() ? 1.4 : 1.6)
.build()Color and Background
Text Colors
// Static color
Text("Colored text")
.modifier
.foregroundColor('#FF6B6B')
.build()
// Reactive color
const [isDark, setIsDark] = createSignal(false)
Text("Theme-aware text")
.modifier
.foregroundColor(() => isDark() ? '#FFFFFF' : '#000000')
.build()Background Colors
Text("Text with background")
.modifier
.backgroundColor('#FFE66D')
.padding(8)
.cornerRadius(4)
.build()Layout Integration
Text in Layouts
import { VStack, HStack } from '@tachui/core'
VStack([
TextStyles.Title("Article Title")
.modifier
.textAlign('center')
.build(),
HStack([
TextStyles.Caption("By Author")
.modifier
.opacity(0.7)
.build(),
Spacer(),
TextStyles.Caption("2 min read")
.modifier
.opacity(0.7)
.build()
]),
TextStyles.Body("Article content goes here...")
.modifier
.lineHeight(1.6)
.build()
])Common Patterns
Article Header
const ArticleHeader = (title: string, author: string, date: string) =>
VStack([
TextStyles.LargeTitle(title)
.modifier
.textAlign('center')
.marginBottom(16)
.build(),
HStack([
TextStyles.Subheadline(`By ${author}`)
.modifier
.opacity(0.8)
.build(),
TextStyles.Subheadline(" • ")
.modifier
.opacity(0.5)
.build(),
TextStyles.Subheadline(date)
.modifier
.opacity(0.8)
.build()
])
.modifier
.justifyContent('center')
.marginBottom(24)
.build()
])Code Block
const CodeBlock = (code: string) =>
TextFormat.monospace(code)
.modifier
.backgroundColor('#1e1e1e')
.foregroundColor('#d4d4d4')
.padding(16)
.cornerRadius(8)
.fontSize(14)
.lineHeight(1.5)
.overflowX('auto')
.build()Badge/Tag
const Badge = (text: string, color: string = '#007AFF') =>
TextStyles.Caption(text)
.modifier
.backgroundColor(color)
.foregroundColor('#FFFFFF')
.padding({ horizontal: 8, vertical: 4 })
.cornerRadius(12)
.fontSize(12)
.fontWeight('600')
.textTransform('uppercase')
.letterSpacing('0.5px')
.build()Link Text
const LinkText = (text: string, url: string) =>
Text(text)
.modifier
.foregroundColor('#007AFF')
.textDecoration('underline')
.cursor('pointer')
.onTap(() => window.open(url, '_blank'))
.onHover((hovered) => hovered ?
{ opacity: 0.7 } :
{ opacity: 1 }
)
.build()Performance Considerations
Text Memoization
For expensive text computations, use memoization:
import { createMemo } from '@tachui/core'
const [data, setData] = createSignal([])
const formattedText = createMemo(() =>
data().map(item => item.name).join(', ')
)
Text(formattedText)
.modifier
.build()Large Text Lists
For large amounts of text content, consider virtualization:
import { List } from '@tachui/core'
const LargeTextList = ({ items }: { items: string[] }) =>
List({
data: items,
renderItem: (text, index) =>
TextStyles.Body(text)
.modifier
.padding(8)
.build()
})API Reference
Text Function
Text(
content: string | (() => string) | Signal<string>,
props?: Omit<TextProps, 'content'>
): ModifiableComponent<TextProps>TextProps Interface
interface TextProps {
content?: string | (() => string) | Signal<string>
// Typography
font?: {
family?: string
size?: number | string
weight?: string
style?: 'normal' | 'italic' | 'oblique'
variant?: 'normal' | 'small-caps'
}
// Styling
color?: string | Signal<string>
backgroundColor?: string | Signal<string>
textAlign?: 'left' | 'center' | 'right' | 'justify'
textDecoration?: 'none' | 'underline' | 'line-through' | 'overline'
textTransform?: 'none' | 'uppercase' | 'lowercase' | 'capitalize'
lineHeight?: number | string
letterSpacing?: number | string
wordSpacing?: number | string
// Layout
lineLimit?: number
truncationMode?: 'head' | 'tail' | 'middle'
allowsSelection?: boolean
// Accessibility
accessibilityLabel?: string
accessibilityRole?: 'text' | 'heading' | 'label'
accessibilityLevel?: 1 | 2 | 3 | 4 | 5 | 6
// Interactive
onTap?: () => void
onLongPress?: () => void
}Typography Presets
const Typography = {
largeTitle: { size: 34, weight: '400', lineHeight: 1.2 },
title: { size: 28, weight: '400', lineHeight: 1.3 },
title2: { size: 22, weight: '400', lineHeight: 1.3 },
title3: { size: 20, weight: '400', lineHeight: 1.4 },
headline: { size: 17, weight: '600', lineHeight: 1.4 },
body: { size: 17, weight: '400', lineHeight: 1.5 },
callout: { size: 16, weight: '400', lineHeight: 1.4 },
subheadline: { size: 15, weight: '400', lineHeight: 1.4 },
footnote: { size: 13, weight: '400', lineHeight: 1.3 },
caption: { size: 12, weight: '400', lineHeight: 1.2 },
caption2: { size: 11, weight: '400', lineHeight: 1.1 }
}HTML Content Rendering
.asHTML() Modifier
The Text component supports secure HTML content rendering through the .asHTML() modifier, which includes built-in XSS protection and sanitization.
⚠️ Security Notice: The
.asHTML()modifier can only be used with Text components and includes basic sanitization by default. For production applications handling untrusted content, consider using DOMPurify.
Basic HTML Rendering
import { Text } from '@tachui/core'
// Simple HTML content
Text('<p>Welcome to <strong>TachUI</strong>!</p>')
.modifier
.asHTML()
.build()
// Rich content with styling
Text(`
<article>
<h2>Getting Started</h2>
<p>TachUI provides a <em>SwiftUI-inspired</em> development experience.</p>
<ul>
<li>Reactive state management</li>
<li>Type-safe components</li>
<li>Built-in security</li>
</ul>
<blockquote>
"The future of web development is declarative."
</blockquote>
</article>
`)
.modifier
.asHTML()
.padding(20)
.backgroundColor('#F8F9FA')
.cornerRadius(8)
.build()Security Features
The .asHTML() modifier automatically protects against common XSS attacks:
// Dangerous content is automatically sanitized
Text('<script>alert("xss")</script><p>Safe content</p>')
.modifier
.asHTML()
.build()
// Result: '<p>Safe content</p>' (script removed)
Text('<img src="x" onerror="alert(1)" alt="Image">')
.modifier
.asHTML()
.build()
// Result: '<img src="x" alt="Image">' (event handler removed)Custom Sanitization
import DOMPurify from 'dompurify'
// Using DOMPurify for comprehensive sanitization
Text(userGeneratedContent)
.modifier
.asHTML({
customSanitizer: (html: string) => DOMPurify.sanitize(html)
})
.build()
// Restrict to specific tags
Text(blogContent)
.modifier
.asHTML({
allowedTags: ['p', 'strong', 'em', 'a', 'ul', 'li', 'blockquote'],
allowedAttributes: {
'*': ['class'],
'a': ['href', 'target', 'rel']
}
})
.build()Content Types and Security Levels
// User comments - Maximum security
Text(userComment)
.modifier
.asHTML({
allowedTags: ['p', 'strong', 'em', 'br'],
allowedAttributes: {}
})
.build()
// Editorial content - Balanced security
Text(articleContent)
.modifier
.asHTML({
allowedTags: ['p', 'strong', 'em', 'a', 'ul', 'li', 'h1', 'h2', 'h3'],
allowedAttributes: {
'*': ['class'],
'a': ['href', 'target', 'rel']
}
})
.build()
// Trusted server content - Skip sanitization (use with caution)
Text(trustedTemplate)
.modifier
.asHTML({
skipSanitizer: true,
__suppressWarnings: true
})
.build()For comprehensive documentation on secure HTML rendering, see the HTML Content Security Guide.
Best Practices
- Use Typography Presets: Start with built-in presets for consistency
- Reactive Content: Use signals for dynamic text that needs updates
- Accessibility: Always provide proper accessibility roles for semantic text
- Performance: Memoize expensive text computations
- Responsive: Consider mobile-first responsive typography
- Contrast: Ensure sufficient color contrast for readability
- Line Height: Use appropriate line height (1.4-1.6) for readability
Troubleshooting
Text Not Updating
- Ensure you're using signals or reactive functions for dynamic content
- Check that the signal is properly set up with
createSignal
Styling Not Applied
- Remember that styling is applied through the modifier system
- Use
.modifierbefore applying styles
Poor Performance with Large Text
- Consider text virtualization for very large amounts of text
- Use
createMemofor expensive text computations - Debounce rapid text updates
Accessibility Issues
- Always provide
accessibilityLabelfor non-text content (emojis, symbols) - Use proper heading hierarchy with
accessibilityLevel - Ensure sufficient color contrast ratios