Text & Typography
Text is the composable you'll write more than any other, and it looks deceptively
simple — one required parameter, text, and everything else optional. But those
optional parameters are where real UI polish lives: how the text is styled, whether it wraps, and
what happens when a RecipeBox recipe title is simply too long for the space it's given.
Key Parameters: style, color, fontWeight
@Composable
fun SectionHeading(text: String) {
Text(
text = text,
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.primary,
fontWeight = FontWeight.Bold
)
}
style— aTextStylebundling font size, line height, letter spacing, and default weight. Almost always sourced fromMaterialTheme.typographyrather than built by hand (see below).color— overrides the text color from whateverstylespecifies. Sourcing it fromMaterialTheme.colorScheme(rather than a hardcodedColor(0xFF...)) keeps it correct automatically in dark mode.fontWeight—FontWeight.Normal,Medium,Bold, and more; layers on top of whatever thestylealready sets.
Use MaterialTheme.typography, Not Hardcoded Sizes
It's tempting to write fontSize = 22.sp directly, but that scatters magic numbers
across every screen and makes a future type-scale redesign painful. Material 3 defines a
Typography object with named presets — displayLarge,
headlineSmall, titleMedium, bodyLarge,
bodySmall, labelSmall, and more — accessible anywhere through
MaterialTheme.typography:
// Avoid: a hardcoded, one-off size
Text(text = title, fontSize = 22.sp, fontWeight = FontWeight.Bold)
// Prefer: a named preset from the theme's type scale
Text(text = title, style = MaterialTheme.typography.titleLarge)
Using the preset means every recipe title across RecipeBox — list items, the detail screen, the
add/edit form — stays visually consistent, and a single change to the app's
Typography definition (covered later in
Typography Customization) updates every screen
at once.
maxLines and overflow
By default, Text wraps onto as many lines as it needs and never truncates. For a
recipe list item, an unusually long title ("Grandma's Slow-Braised Sunday Pot Roast with Root
Vegetables") would otherwise push the row's height around unpredictably. Constrain it with
maxLines and tell Compose what to do with the leftover text via overflow:
@Composable
fun RecipeTitle(title: String, modifier: Modifier = Modifier) {
Text(
text = title,
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = modifier
)
}
maxLines = 1 caps the title to a single line, and TextOverflow.Ellipsis
replaces whatever text doesn't fit with a trailing … — so
"Grandma's Slow-Braised Sunday Pot Roast with Root Vegetables" renders as something like
"Grandma's Slow-Braised Sunday Pot…", and every row in the list stays exactly one line
tall no matter how long its title is.
| TextOverflow value | Behavior when text exceeds maxLines |
|---|---|
TextOverflow.Clip | Text is cut off abruptly at the boundary, no ellipsis (the default). |
TextOverflow.Ellipsis | Cut off with a trailing … — what RecipeBox uses for titles. |
TextOverflow.Visible | Text is allowed to draw outside its own bounds, overlapping neighboring content. |
onTextLayout
callback (checking result.hasVisualOverflow) if you need to react to it — for example,
showing a "read more" affordance only when a description actually got cut off.