Complete Guide to SwiftUI Text Modifiers: Font Styling and Layout Control

A systematic overview of commonly used Modifiers for SwiftUI's Text component.
This article systematically covers the various Modifiers for SwiftUI's Text component, including font settings (preset styles and custom system fonts), line limit control (lineLimit and reservesSpace), text style modifiers (weight, italic, strikethrough, baseline offset, kerning), truncation and alignment, text scaling (minimumScaleFactor), and interaction features like text selection, helping developers fully master text styling control.
Overview
Text is one of the most fundamental and commonly used view components in SwiftUI. Through various ViewModifiers, we can achieve fine-grained control over text font, style, layout, and more. This article systematically covers the commonly used Modifiers for the Text component in SwiftUI, helping developers quickly master various text styling techniques.

Font Settings
Preset Font Styles
SwiftUI provides a series of preset font styles that developers can use directly without worrying about specific font sizes:
Text("Hello")
.font(.largeTitle)
Text("Hello")
.font(.title)
Text("Hello")
.font(.body)
These preset styles include largeTitle, title, title2, title3, headline, body, callout, footnote, caption, and more. They automatically adjust their size based on the system's dynamic type settings, making them Apple's recommended best practice.
These preset font styles rely on Apple's Dynamic Type system under the hood. Dynamic Type allows users to adjust their preferred text size in system settings, ranging from xSmall to AX5 (accessibility extra-large) across 12 levels. When developers use preset styles, text automatically responds to user preferences, which is particularly important for users with visual impairments. Apple's Human Interface Guidelines (HIG) strongly recommend prioritizing these semantic font styles over hard-coded fixed sizes, as this not only improves accessibility but also ensures consistent visual hierarchy across different devices and system versions.
Custom System Fonts
If preset styles don't meet your needs, you can use system fonts for more granular control:
// Initialize with size
Text("Hello")
.font(.system(size: 20, weight: .black, design: .rounded))
// Initialize with style
Text("Hello")
.font(.system(.title, design: .monospaced))
The design parameter supports various styles including .default, .rounded, .monospaced, and .serif.
These design styles correspond to different variants of the San Francisco font family: .default uses standard SF Pro; .rounded uses SF Pro Rounded, with rounded stroke endings commonly seen in fitness, weather, and other casual-style apps; .monospaced uses SF Mono, where each character has equal width, ideal for code display and number alignment; .serif uses the New York font with serif characteristics, suitable for long-form reading. These design variants share the same metrics, so mixing them within the same interface won't cause layout misalignment.
Using Platform Fonts
For scenarios requiring specific system fonts, you can initialize through the platform font API:
// iOS uses UIFont, macOS uses NSFont
Text("Hello")
.font(Font(UIFont(name: "Helvetica", size: 18)!))
Note that force unwrapping (!) is used here, so you must ensure the font name exists. Importing and using custom fonts will be covered in detail in later sections.
Line Limit Control
Basic Line Limit
lineLimit is the core Modifier for controlling the number of displayed text lines:
// Display up to 4 lines
Text(longText)
.lineLimit(4)
When the actual number of lines is less than the limit, text displays at its actual line count; when it exceeds the limit, it gets truncated.
Range-Based Line Limit
SwiftUI also supports setting a line count range for more flexible layout control:
// Minimum 3 lines, maximum 5 lines
Text(longText)
.lineLimit(3...5)
This means: when text exceeds 5 lines, only 5 lines are shown; when text is fewer than 3 lines, the view still maintains the height of 3 lines. This is very practical in scenarios where uniform layout height is needed.
Fixed Line Count with Reserved Space
// Fixed 3-line height, even if content is only 2 lines
Text(shortText)
.lineLimit(3, reservesSpace: true)
With reservesSpace: true, even if the text content doesn't fill the specified number of lines, the view reserves the corresponding height space, preventing layout jumps.
The working principle of lineLimit is closely tied to SwiftUI's layout negotiation mechanism. In SwiftUI, parent views propose available space (proposed size) to child views, and child views return the actual size they need based on their content. When the Text view calculates its height, it uses lineLimit as one of its constraints. When a range value (like 3...5) is set, Text attempts to find the optimal line count within this range during layout negotiation—prioritizing complete content display without exceeding the upper limit. The reservesSpace parameter changes Text's size reporting strategy, making it always report height based on the specified line count, which is particularly useful for maintaining equal card heights in LazyVGrid or lists.
Text Style Modifiers
Font Weight and Italic
// Bold
Text("Bold").bold()
// Italic
Text("Italic").italic()
Text("Italic").italic(true) // Can pass a boolean to control
// Set font weight independently
Text("Heavy").fontWeight(.heavy)
Strikethrough and Underline
// Strikethrough
Text("Strikethrough")
.strikethrough(true, color: .red)
// Underline
Text("Underline")
.underline(true, color: .blue)
Both support an active parameter to control visibility and a color parameter to set the line color.
Baseline Offset
baselineOffset allows fine vertical adjustment of text:
Text("Learn SwiftUI") + Text("...").baselineOffset(5)
A typical use case is when you need ellipsis or special symbols to vertically center-align with the main text—you can achieve this by adjusting the baseline offset. A noteworthy detail: baselineOffset returns a Text type, so it can be used with the + operator for text concatenation.
The + operator support for Text concatenation in SwiftUI is a carefully designed feature. Unlike String concatenation, Text concatenation preserves independent style information for each segment. This is possible because Text internally uses a storage structure similar to attributed strings. It's important to note that only modifiers returning Text type (such as bold(), foregroundColor(), baselineOffset(), etc.) can participate in concatenation, while modifiers returning some View (such as padding(), frame()) cannot. This design allows developers to achieve multi-style text composition within a single Text view, similar to NSAttributedString in UIKit, but with much more concise and intuitive syntax.
Kerning and Text Case
// Letter spacing
Text("Spacing").kerning(2)
// Case transformation
Text("Hello").textCase(.uppercase) // All uppercase
Text("Hello").textCase(.lowercase) // All lowercase
Truncation and Alignment
Truncation Mode
When text exceeds the display area, you can choose where truncation occurs:
Text(longText)
.lineLimit(1)
.truncationMode(.tail) // Tail truncation (default)
.truncationMode(.head) // Head truncation
.truncationMode(.middle) // Middle truncation
Multiline Text Alignment
Text(multilineText)
.multilineTextAlignment(.center) // Center alignment
.multilineTextAlignment(.trailing) // Trailing alignment
Text Scaling and Interaction
Minimum Scale Factor
On smaller devices, text may not display completely. By setting a minimum scale factor, text can automatically shrink to fit the available space:
Text("A very long title text")
.font(.largeTitle)
.lineLimit(1)
.minimumScaleFactor(0.6) // Scale down to minimum 60%
The parameter ranges from 0 to 1, representing the percentage of the original size that text is allowed to shrink to. This is very useful when adapting to different screen sizes.
The way minimumScaleFactor works is: SwiftUI first attempts to render text at its original font size. If it detects that text overflows the available space, it progressively reduces the font size until the text fits completely or reaches the minimum scale ratio. This process occurs during the layout phase and doesn't incur additional rendering overhead. Notably, scaling is applied uniformly to the entire Text view—you won't see some characters larger and others smaller. In practice, it's recommended to set the minimum scale factor above 0.5, as text that's too small severely impacts readability. Additionally, minimumScaleFactor is typically used in conjunction with lineLimit(1) to ensure title-type text adapts within a single line.
Text Selection
Text("Selectable text")
.textSelection(.enabled)
Once enabled, text can be selected with the mouse on macOS, or via long press on iOS.
Font Width (iOS 16+)
Starting with macOS 13 and iOS 16, SwiftUI introduced the fontWidth modifier, which adjusts font width characteristics, providing more possibilities for text typography.
The fontWidth modifier relies on Variable Fonts technology under the hood. Variable fonts are a feature introduced in the OpenType 1.8 specification, allowing a single font file to contain multiple design axes (such as width, weight, optical size, etc.) that generate infinite variations through continuous interpolation. Apple's SF Pro font supports the width axis starting from iOS 16, providing four preset widths: compressed, condensed, standard, and expanded. This means developers can use narrow fonts in compact spaces and wide fonts in spacious layouts without loading multiple font files, while maintaining font style consistency.
Summary
SwiftUI's Text Modifier system is very well-designed, covering most text styling needs in daily development—from basic font settings to fine-grained layout control. Mastering the combined use of these Modifiers can make your interface text appear more professional and polished. Developers are encouraged to practice extensively in real projects, leveraging Xcode's live preview feature to quickly debug and iterate on results.
Key Takeaways
- SwiftUI offers two approaches for text fonts: preset font styles (largeTitle, title, body, etc.) and custom system fonts
- lineLimit supports fixed values, range values, and the reservesSpace parameter for flexible line count and height control
- baselineOffset returns a Text type, enabling vertical alignment fine-tuning when concatenating text with the + operator
- minimumScaleFactor allows text to automatically scale down when space is insufficient, with a parameter range of 0-1 representing the minimum scale ratio
- iOS 16 introduced modern text interaction features like fontWidth and textSelection
Related articles
TutorialsCursor + Codex Dual-IDE Collaboration: A Practical Methodology for Open-Source Project Customization
A complete methodology for open-source project customization based on real-world experience, detailing the Cursor+Codex dual-IDE workflow, seven-stage process, MVP validation, and AI source code reading techniques.
TutorialsCursor Multi-Agent in Practice: Building a Full-Stack Next.js Blog in 50 Minutes
Build a full-stack blog in 50 minutes using Cursor IDE's multi-Agent mode with Next.js, Clerk auth, and Supabase. Learn the 4-phase AI Agent workflow and key integration pitfalls.
TutorialsBuilding an AI Software Factory from Scratch: A Cursor Engineer's Hands-On Experience with Multi-Agent Collaboration
Cursor engineer Eric shares practical insights on building an AI software factory: automation levels, guardrail design, parallel Agent management, and scaling to 1000+ Agents for 24/7 development.