$npx -y skills add rshankras/claude-code-apple-skills --skill attributed-stringAttributedString patterns for rich text formatting, alignment, selection, and SwiftUI integration. Use when working with styled text, text editing, or AttributedString APIs.
| 1 | # AttributedString Patterns |
| 2 | |
| 3 | Correct API shapes and patterns for Foundation's `AttributedString`. Covers creating styled text, applying attributes to ranges, text alignment, writing direction, line height control, text selection and editing, discontiguous substrings, and SwiftUI integration. |
| 4 | |
| 5 | ## When This Skill Activates |
| 6 | |
| 7 | Use this skill when the user: |
| 8 | - Asks about **AttributedString** creation or manipulation |
| 9 | - Wants to **style text** with fonts, colors, underlines, or other attributes |
| 10 | - Mentions **text alignment**, **writing direction**, or **line height** |
| 11 | - Asks about **text selection** or **text editing** with AttributedString |
| 12 | - Wants to work with **DiscontiguousAttributedSubstring** or **RangeSet** |
| 13 | - Mentions **TextEditor** with **AttributedString** in SwiftUI |
| 14 | - Asks about **rich text** formatting in Swift |
| 15 | - Wants to **replace** or **modify** text within an AttributedString |
| 16 | - Mentions **paragraphStyle**, **textSelectionAffinity**, or **AttributedTextSelection** |
| 17 | |
| 18 | ## Decision Tree |
| 19 | |
| 20 | ``` |
| 21 | What do you need with AttributedString? |
| 22 | | |
| 23 | +-- Create or style text |
| 24 | | | |
| 25 | | +-- Simple inline attributes (font, color) |
| 26 | | | --> Creating and Styling section |
| 27 | | | |
| 28 | | +-- Paragraph-level formatting (alignment, line height) |
| 29 | | --> Text Alignment and Formatting section |
| 30 | | |
| 31 | +-- Control text layout |
| 32 | | | |
| 33 | | +-- Writing direction (LTR / RTL) |
| 34 | | | --> Writing Direction and Line Height section |
| 35 | | | |
| 36 | | +-- Line spacing / height |
| 37 | | --> Writing Direction and Line Height section |
| 38 | | |
| 39 | +-- Edit or select text programmatically |
| 40 | | | |
| 41 | | +-- Replace selection with characters or AttributedString |
| 42 | | | --> Text Selection and Editing section |
| 43 | | | |
| 44 | | +-- Work with multiple non-contiguous ranges |
| 45 | | --> DiscontiguousAttributedSubstring section |
| 46 | | |
| 47 | +-- Display in SwiftUI |
| 48 | --> SwiftUI Integration section |
| 49 | ``` |
| 50 | |
| 51 | ## API Availability |
| 52 | |
| 53 | | API | Minimum Version | Notes | |
| 54 | |-----|----------------|-------| |
| 55 | | `AttributedString` | iOS 15 / macOS 12 | Swift-native replacement for NSAttributedString | |
| 56 | | `AttributedString.paragraphStyle` | iOS 15 / macOS 12 | Uses NSMutableParagraphStyle | |
| 57 | | `AttributedString.writingDirection` | iOS 26 / macOS 26 | New in 2025 | |
| 58 | | `AttributedString.LineHeight` | iOS 26 / macOS 26 | `.exact(points:)`, `.multiple(factor:)`, `.loose` | |
| 59 | | `AttributedString.alignment` | iOS 26 / macOS 26 | `.left`, `.center`, `.right` | |
| 60 | | `AttributedTextSelection` | iOS 26 / macOS 26 | Programmatic text selection | |
| 61 | | `replaceSelection(_:withCharacters:)` | iOS 26 / macOS 26 | Replace selection with plain characters | |
| 62 | | `replaceSelection(_:with:)` | iOS 26 / macOS 26 | Replace selection with AttributedString | |
| 63 | | `DiscontiguousAttributedSubstring` | iOS 26 / macOS 26 | Non-contiguous range selections | |
| 64 | | `AttributedString.utf8` | iOS 26 / macOS 26 | UTF-8 code unit view | |
| 65 | | `TextEditor(text:selection:)` with AttributedString | iOS 26 / macOS 26 | SwiftUI rich text editing | |
| 66 | | `.textSelectionAffinity(_:)` | iOS 26 / macOS 26 | Control cursor affinity at line boundaries | |
| 67 | |
| 68 | ## Top 5 Mistakes |
| 69 | |
| 70 | | # | Mistake | Fix | |
| 71 | |---|---------|-----| |
| 72 | | 1 | Using `NSAttributedString` in new Swift code | Use `AttributedString` (iOS 15+) for type-safe, Swift-native attributes | |
| 73 | | 2 | Applying range-based attributes without checking the range exists | Always safely unwrap the result of `text.range(of:)` before subscripting | |
| 74 | | 3 | Forgetting that `AttributedString` is a value type | Mutations require `var`, not `let`; assign attributes after declaring as `var` | |
| 75 | | 4 | Building `NSMutableParagraphStyle` when new alignment API is available | Use `text.alignment = .center` on iOS 26+ instead of manual paragraph styles | |
| 76 | | 5 | Modifying the original string instead of the selection when using `replaceSelection` | Pass the selection as `inout` and let the API update the selection range for you | |
| 77 | |
| 78 | ## Creating and Styling |
| 79 | |
| 80 | ### Basic Initialization |
| 81 | |
| 82 | ```swift |
| 83 | // Plain text |
| 84 | let plain = AttributedString("Hello, world!") |
| 85 | |
| 86 | // With attributes applied inline |
| 87 | var bold = AttributedString("Bold text") |
| 88 | bold.font = .boldSystemFont(ofSize: 16) |
| 89 | ``` |
| 90 | |
| 91 | ### Applying Attributes to Ranges |
| 92 | |
| 93 | ```swift |
| 94 | var text = AttributedString("Styled text") |
| 95 | text.foregroundColor = .red |
| 96 | text.backgroundColor = .yellow |
| 97 | text.font = .systemFont(ofSize: 14) |
| 98 | |
| 99 | // Attribute on a specific range |
| 100 | if let range = text.range(of: "Styled") { |
| 101 | text[range].underlineStyle = .single |
| 102 | text[range].underlineColor = .blue |
| 103 | } |
| 104 | ``` |
| 105 | |
| 106 | ### Creating from a Substring |
| 107 | |
| 108 | ```swift |
| 109 | let source = AttributedString("Hello, world!") |
| 110 | if let range = source.range(of: "world") { |
| 111 | let substring = source[range] |
| 112 | let extracted = AttributedString(substring) // standalone copy |
| 113 | } |
| 114 | ``` |
| 115 | |
| 116 | | Pattern | Verdict | |
| 117 | |-- |