TextUtils provides a comprehensive collection of pre-styled text components for common typography patterns in Summon applications. These components offer semantic meaning, consistent styling, and accessibility features out of the box.
Typography is fundamental to good user experience. TextUtils components provide:
Semantic heading components that correspond to HTML heading elements.
import code.yousef.summon.components.display.*
@Composable
fun HeadingExample() {
Column(verticalSpacing = "16px") {
H1("Main Page Title")
H2("Section Heading")
H3("Subsection Heading")
}
}
@Composable
fun H1(
text: String,
modifier: Modifier = Modifier(),
ariaLevel: Int? = null
)
@Composable
fun H2(
text: String,
modifier: Modifier = Modifier(),
ariaLevel: Int? = null
)
@Composable
fun H3(
text: String,
modifier: Modifier = Modifier(),
ariaLevel: Int? = null
)
| Component | Font Size | Font Weight | Margin | Use Case | |-----------|------------------|-------------|-------------------|----------------------------| | H1 | 2rem (32px) | Bold | 0.67em top/bottom | Page titles, main headings | | H2 | 1.5rem (24px) | Bold | 0.83em top/bottom | Section headings | | H3 | 1.17rem (18.7px) | Bold | 1em top/bottom | Subsection headings |
Standard paragraph text with appropriate line height and spacing.
@Composable
fun ParagraphExample() {
Paragraph(
text = "This is a standard paragraph with proper line height and spacing for optimal readability."
)
}
Smaller secondary text for descriptions, metadata, or fine print.
@Composable
fun CaptionExample() {
Column(verticalSpacing = "8px") {
Text("John Doe", fontSize = "16px", fontWeight = "medium")
Caption("Software Engineer at Tech Corp")
}
}
Text for form labels or descriptive text above inputs.
@Composable
fun LabelExample() {
Column(verticalSpacing = "4px") {
Label("Email Address")
TextField(
value = email,
onValueChange = { email = it },
placeholder = "Enter your email"
)
}
}
Styled text for code snippets, file paths, or technical content.
@Composable
fun MonospaceExample() {
Column(verticalSpacing = "12px") {
Paragraph("To install the package, run:")
Monospace("npm install @summon/ui")
Paragraph("Then import it in your file:")
Monospace("import { Button } from '@summon/ui'")
}
}
Colored text for status messages and feedback.
@Composable
fun StatusTextExample() {
Column(verticalSpacing = "8px") {
SuccessText("File uploaded successfully!")
ErrorText("Invalid email format")
}
}
Text with emphasis using italics or bold styling.
@Composable
fun EmphasisExample() {
Paragraph(
text = buildString {
append("This is ")
append("important")
append(" and this is ")
append("emphasized")
append(" text.")
}
)
// Using individual components
Row(horizontalSpacing = "4px") {
Text("This is ")
StrongText("important")
Text(" and this is ")
EmphasizedText("emphasized")
Text(" text.")
}
}
Styled blockquote text with left border and italic styling.
@Composable
fun QuoteExample() {
Column(verticalSpacing = "16px") {
Paragraph("As Steve Jobs once said:")
QuoteText(
"Innovation distinguishes between a leader and a follower."
)
}
}
Text that truncates after a specified number of lines with ellipsis.
@Composable
fun TruncatedTextExample() {
TruncatedText(
text = "This is a very long text that would normally wrap to many lines, but we want to limit it to just two lines for better layout control.",
maxLines = 2,
modifier = Modifier().width("300px")
)
}
Styled text for displaying keyboard shortcuts.
@Composable
fun KeyboardShortcutExample() {
Row(
horizontalSpacing = "8px",
verticalAlignment = "center"
) {
Text("Copy:")
KeyboardText("Ctrl+C")
Text("Paste:")
KeyboardText("Ctrl+V")
}
}
Pill-shaped badge text with customizable colors.
@Composable
fun BadgeExample() {
Row(horizontalSpacing = "8px") {
BadgeText("New", color = "#E3F2FD", textColor = "#1976D2")
BadgeText("Hot", color = "#FFEBEE", textColor = "#D32F2F")
BadgeText("Sale", color = "#E8F5E8", textColor = "#2E7D32")
}
}
Visually hidden text that's accessible to screen readers.
@Composable
fun AccessibleButtonExample() {
Button(
onClick = { deleteItem() },
modifier = Modifier().ariaLabel("Delete item")
) {
Icon("delete")
ScreenReaderText("Delete") // Hidden but announced by screen readers
}
}
// Headings
@Composable fun H1(text: String, modifier: Modifier = Modifier(), ariaLevel: Int? = null)
@Composable fun H2(text: String, modifier: Modifier = Modifier(), ariaLevel: Int? = null)
@Composable fun H3(text: String, modifier: Modifier = Modifier(), ariaLevel: Int? = null)
// Body text
@Composable fun Paragraph(text: String, modifier: Modifier = Modifier())
@Composable fun Caption(text: String, modifier: Modifier = Modifier())
@Composable fun Label(text: String, modifier: Modifier = Modifier())
// Technical text
@Composable fun Monospace(text: String, modifier: Modifier = Modifier())
@Composable fun KeyboardText(text: String, modifier: Modifier = Modifier())
// Status text
@Composable fun ErrorText(text: String, modifier: Modifier = Modifier())
@Composable fun SuccessText(text: String, modifier: Modifier = Modifier())
// Emphasis
@Composable fun EmphasizedText(text: String, modifier: Modifier = Modifier())
@Composable fun StrongText(text: String, modifier: Modifier = Modifier())
// Special formatting
@Composable fun QuoteText(text: String, modifier: Modifier = Modifier())
@Composable fun TruncatedText(text: String, maxLines: Int, modifier: Modifier = Modifier())
@Composable fun BadgeText(text: String, color: String = "#e0e0e0", textColor: String = "#333333", modifier: Modifier = Modifier())
// Accessibility
@Composable fun ScreenReaderText(text: String)
@Composable
fun ArticleLayout() {
Column(
modifier = Modifier()
.maxWidth("800px")
.margin("0 auto")
.padding("24px"),
verticalSpacing = "16px"
) {
// Article header
H1("Understanding Kotlin Multiplatform")
Caption("Published on March 15, 2024 by Jane Developer")
// Article content
Paragraph(
"Kotlin Multiplatform is a powerful technology that allows developers to share code between different platforms while maintaining the flexibility to write platform-specific code when needed."
)
H2("Key Benefits")
Paragraph(
"The main advantages of using Kotlin Multiplatform include code reuse, consistent business logic, and reduced maintenance overhead."
)
H3("Code Sharing")
Paragraph(
"Share your business logic, networking, and data models across platforms:"
)
Monospace("expect class Platform() { fun name(): String }")
H3("Platform-Specific Implementation")
Paragraph(
"Implement platform-specific features when needed:"
)
Monospace("actual class Platform actual constructor() { actual fun name(): String = \"Android\" }")
QuoteText(
"Kotlin Multiplatform doesn't try to make everything common. It makes the parts that can be common, common, and leaves the rest platform-specific."
)
}
}
@Composable
fun RegistrationForm() {
var email by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
var error by remember { mutableStateOf<String?>(null) }
var success by remember { mutableStateOf(false) }
Column(
modifier = Modifier().padding("24px"),
verticalSpacing = "16px"
) {
H2("Create Account")
// Email field
Column(verticalSpacing = "4px") {
Label("Email Address")
TextField(
value = email,
onValueChange = { email = it },
placeholder = "Enter your email"
)
}
// Password field
Column(verticalSpacing = "4px") {
Label("Password")
TextField(
value = password,
onValueChange = { password = it },
type = "password",
placeholder = "Enter your password"
)
Caption("Must be at least 8 characters long")
}
// Status messages
error?.let { ErrorText(it) }
if (success) {
SuccessText("Account created successfully!")
}
Button(
text = "Create Account",
onClick = { submitForm(email, password) }
)
Caption(
buildString {
append("By creating an account, you agree to our ")
append("Terms of Service")
append(" and ")
append("Privacy Policy")
append(".")
}
)
}
}
@Composable
fun HelpSection() {
Column(verticalSpacing = "20px") {
H2("Keyboard Shortcuts")
Row(
modifier = Modifier().justifyContent("space-between"),
horizontalSpacing = "16px"
) {
Column(verticalSpacing = "8px") {
Row(horizontalSpacing = "12px") {
KeyboardText("Ctrl+S")
Text("Save document")
}
Row(horizontalSpacing = "12px") {
KeyboardText("Ctrl+Z")
Text("Undo")
}
Row(horizontalSpacing = "12px") {
KeyboardText("Ctrl+Y")
Text("Redo")
}
}
Column(verticalSpacing = "8px") {
Row(horizontalSpacing = "12px") {
KeyboardText("Ctrl+F")
Text("Find")
}
Row(horizontalSpacing = "12px") {
KeyboardText("Ctrl+H")
Text("Replace")
}
Row(horizontalSpacing = "12px") {
KeyboardText("F11")
Text("Fullscreen")
}
}
}
H3("Pro Tips")
Row(horizontalSpacing = "8px") {
BadgeText("Tip", color = "#FFF3E0", textColor = "#F57C00")
Text("Use")
KeyboardText("Ctrl+Shift+P")
Text("to open the command palette")
}
}
}
@Composable
fun ProductCard(product: Product) {
Card(
modifier = Modifier()
.width("300px")
.padding("16px")
) {
Column(verticalSpacing = "12px") {
// Product badges
Row(horizontalSpacing = "8px") {
if (product.isNew) {
BadgeText("New", color = "#E3F2FD", textColor = "#1976D2")
}
if (product.onSale) {
BadgeText("Sale", color = "#FFEBEE", textColor = "#D32F2F")
}
if (product.featured) {
BadgeText("Featured", color = "#E8F5E8", textColor = "#2E7D32")
}
}
// Product name
StrongText(product.name)
// Product description
TruncatedText(
text = product.description,
maxLines = 2
)
// Price
Row(
horizontalSpacing = "8px",
verticalAlignment = "center"
) {
if (product.originalPrice != product.currentPrice) {
Text(
text = "$${product.originalPrice}",
modifier = Modifier()
.textDecoration("line-through")
.color("#999999")
)
}
StrongText("$${product.currentPrice}")
}
// Technical specs
if (product.specs.isNotEmpty()) {
Column(verticalSpacing = "4px") {
Caption("Specifications:")
product.specs.forEach { spec ->
Row(horizontalSpacing = "8px") {
Text("•")
Caption(spec)
}
}
}
}
}
}
}
Use heading components in logical order:
// Good - Proper heading hierarchy
H1("Page Title")
H2("Main Section")
H3("Subsection")
H3("Another Subsection")
H2("Another Main Section")
// Bad - Skipping heading levels
H1("Page Title")
H3("Subsection") // Skips H2
Use ScreenReaderText for additional context:
@Composable
fun DataTable() {
Column {
H2("Sales Data")
ScreenReaderText("Table showing monthly sales figures for 2024")
// Table content here
}
}
Ensure sufficient contrast for text:
// Good - High contrast error text
ErrorText("Password is required") // #d32f2f on light background
// Consider dark mode alternatives
val errorColor = if (isDarkMode) "#ff6b6b" else "#d32f2f"
ErrorText(
text = "Password is required",
modifier = Modifier().color(errorColor)
)
@Composable
fun ThemedContent() {
val theme = LocalTheme.current
H1(
text = "Welcome",
modifier = Modifier().color(theme.colors.primary)
)
Paragraph(
text = "Content text",
modifier = Modifier().color(theme.colors.onSurface)
)
}
object AppTypography {
@Composable
fun DisplayLarge(text: String, modifier: Modifier = Modifier()) {
Text(
text = text,
modifier = modifier
.fontSize("3.5rem")
.fontWeight("300")
.lineHeight("1.2"),
fontFamily = "system-ui"
)
}
@Composable
fun BodyLarge(text: String, modifier: Modifier = Modifier()) {
Text(
text = text,
modifier = modifier
.fontSize("1.125rem")
.lineHeight("1.6"),
fontFamily = "system-ui"
)
}
}
The TextUtils components use system fonts for optimal performance:
Consider responsive font sizes for better mobile experience:
@Composable
fun ResponsiveHeading(text: String) {
val breakpoint = LocalBreakpoint.current
val fontSize = when (breakpoint) {
Breakpoint.MOBILE -> "1.5rem"
Breakpoint.TABLET -> "2rem"
Breakpoint.DESKTOP -> "2.5rem"
}
H1(
text = text,
modifier = Modifier().fontSize(fontSize)
)
}
@Test
fun testHeadingComponents() {
val mockRenderer = MockPlatformRenderer()
CompositionLocal.provideComposer(MockComposer()) {
LocalPlatformRenderer.provides(mockRenderer) {
H1("Test Heading")
assertTrue(mockRenderer.renderTextCalled)
assertEquals("Test Heading", mockRenderer.lastTextContentRendered)
val styles = mockRenderer.lastTextModifierRendered?.styles
assertEquals("2rem", styles?.get("font-size"))
assertEquals("bold", styles?.get("font-weight"))
}
}
}
@Test
fun testScreenReaderText() {
val mockRenderer = MockPlatformRenderer()
CompositionLocal.provideComposer(MockComposer()) {
LocalPlatformRenderer.provides(mockRenderer) {
ScreenReaderText("Hidden content")
val styles = mockRenderer.lastTextModifierRendered?.styles
assertEquals("absolute", styles?.get("position"))
assertEquals("1px", styles?.get("width"))
assertEquals("1px", styles?.get("height"))
}
}
}
<!-- HTML -->
<h1>Page Title</h1>
<p>Paragraph content</p>
<small>Caption text</small>
<code>inline code</code>
<strong>bold text</strong>
<em>italic text</em>
// Summon equivalent
H1("Page Title")
Paragraph("Paragraph content")
Caption("Caption text")
Monospace("inline code")
StrongText("bold text")
EmphasizedText("italic text")
/* CSS classes */
.error-text { color: #d32f2f; }
.success-text { color: #2e7d32; }
.badge { background: #e0e0e0; padding: 0.25em 0.6em; border-radius: 1em; }
// Summon components
ErrorText("Error message")
SuccessText("Success message")
BadgeText("Badge text")
TextUtils components provide a solid foundation for typography in your Summon application, ensuring consistency, accessibility, and performance across all platforms.