Typography
Text & Span
How rich text composition works in Sone.
Text(...) is a paragraph block. Span(...) is an inline styled segment inside it. A single Text node can contain a mix of plain strings and Spans, each with its own styling.
Text(
"Revenue grew ",
Span("+22%").color("green").weight("bold"),
" year over year.",
).size(16)This is the core of Sone's rich-text model. There is no separate "rich text" mode — every Text node is rich.
Plain text
When you don't need inline styling, just pass strings:
Text("A simple paragraph of body copy.").size(14).lineHeight(1.6)Mixed strings and spans
Children of Text can be any mix of strings and Spans:
Text(
"We just released ",
Span("v2.0").weight("bold"),
" — ",
Span("read the announcement").color("blue").underline(),
".",
).size(14)Span — what it can do
A Span accepts every text-styling method that Text does, plus a few span-specific ones:
Span("highlighted")
.color("orange")
.weight("bold")
.size(14)
.underline(2)
.highlight("yellow")
.strokeColor("black").strokeWidth(0.5)
.dropShadow("0 1px 2px rgba(0,0,0,0.4)")
.offsetY(-2) // baseline offsetTextDefault — inherited styling
TextDefault(...) cascades text styling to all descendant Text and Span nodes. Useful when many nodes share the same font or color:
TextDefault(
Column(
Text("Heading").size(20).weight("bold"),
Text("Body copy that inherits the font and color.").size(12),
).gap(8),
)
.font("GeistMono")
.color("#111")Per-node properties always win over inherited defaults.
What's next
- Per-property reference — see Styling.
- Multi-line typography — see Balanced wrapping and Hyphenation.
- Tabular content without a table node — see Tab stops.
- Loading custom fonts — see Fonts.