Text Formatting Reference
Use when looking up NSAttributedString.Key values, underline styles, shadows, lists, tables, or view-compatibility rules.
Use when looking up NSAttributedString.Key values, underline styles, shadows, lists, tables, or view-compatibility rules.
Family: Rich Text And Formatting
Use this skill when you already know the formatting problem and need the exact attribute or compatibility rules.
When to Use
Section titled “When to Use”- You need an
NSAttributedString.Keyreference. - You are checking which formatting works in which view.
- You need paragraph-style, underline, shadow, or table-formatting details.
Quick Decision
Section titled “Quick Decision”- Need type choice or custom attribute scopes ->
/skill apple-text-attributed-string - Need exact formatting keys and compatibility -> stay here
- Need semantic text colors rather than general formatting ->
/skill apple-text-colors
Core Guidance
Section titled “Core Guidance”Character-Level Attributes (NSAttributedString.Key)
Section titled “Character-Level Attributes (NSAttributedString.Key)”Typography
Section titled “Typography”| Key | Value Type | Effect | Min OS |
|---|---|---|---|
.font | UIFont / NSFont | Typeface, size, weight | All |
.kern | NSNumber (CGFloat) | Inter-character spacing (points) | All |
.tracking | NSNumber (CGFloat) | Tracking (scales with font size) | iOS 14+ |
.ligature | NSNumber (Int) | 0=none, 1=default, 2=all (macOS only) | All |
.baselineOffset | NSNumber (CGFloat) | Vertical shift from baseline | All |
.obliqueness | NSNumber (CGFloat) | Synthetic italic (0=none, positive=right lean) | All |
.expansion | NSNumber (CGFloat) | Horizontal stretch (0=normal, positive=wider) | All |
.verticalGlyphForm | NSNumber (Int) | 0=horizontal, 1=vertical (CJK) | All |
| Key | Value Type | Effect | Min OS |
|---|---|---|---|
.foregroundColor | UIColor / NSColor | Text color | All |
.backgroundColor | UIColor / NSColor | Background behind text | All |
.strokeColor | UIColor / NSColor | Text outline color | All |
.strokeWidth | NSNumber (CGFloat) | Outline width. Negative = fill + stroke | All |
.shadow | NSShadow | Drop shadow | All |
Decoration
Section titled “Decoration”| Key | Value Type | Effect | Min OS |
|---|---|---|---|
.underlineStyle | NSNumber (NSUnderlineStyle) | Underline pattern | All |
.underlineColor | UIColor / NSColor | Underline color (nil = foreground color) | All |
.strikethroughStyle | NSNumber (NSUnderlineStyle) | Strikethrough pattern | All |
.strikethroughColor | UIColor / NSColor | Strikethrough color | All |
Layout & Structure
Section titled “Layout & Structure”| Key | Value Type | Effect | Min OS |
|---|---|---|---|
.paragraphStyle | NSParagraphStyle | Paragraph formatting (see below) | All |
.writingDirection | [NSNumber] | Embedding/override direction | All |
.textEffect | NSAttributedString.TextEffectStyle | Visual effect | iOS 7+ |
Content
Section titled “Content”| Key | Value Type | Effect | Min OS |
|---|---|---|---|
.attachment | NSTextAttachment | Inline image/view | All |
.link | URL or String | Hyperlink | All |
.textAlternatives | NSTextAlternatives | Alternative text interpretations | iOS 18+ |
.adaptiveImageGlyph | NSAdaptiveImageGlyph | Genmoji/stickers | iOS 18+ |
AppKit-Only
Section titled “AppKit-Only”| Key | Value Type | Effect |
|---|---|---|
.superscript | NSNumber (Int) | Superscript (positive) or subscript (negative) |
.cursor | NSCursor | Mouse cursor when hovering |
.toolTip | String | Hover tooltip |
.markedClauseSegment | NSNumber (Int) | CJK input clause segment |
.spellingState | NSNumber (Int) | Spelling/grammar error indicator |
.glyphInfo | NSGlyphInfo | Glyph substitution |
.textBlock | NSTextBlock | Text block (table cell, etc.) |
NSUnderlineStyle
Section titled “NSUnderlineStyle”Combine with bitwise OR for compound styles:
Line Style
Section titled “Line Style”| Style | Visual |
|---|---|
.single | Single line |
.thick | Thick line |
.double | Double line |
Pattern (Combine with style)
Section titled “Pattern (Combine with style)”| Pattern | Visual |
|---|---|
| (none) | Solid line |
.patternDot | Dotted |
.patternDash | Dashed |
.patternDashDot | Dash-dot |
.patternDashDotDot | Dash-dot-dot |
Modifier
Section titled “Modifier”| Modifier | Effect |
|---|---|
.byWord | Only under words, not spaces |
Examples
Section titled “Examples”// Thick dashed underline, words onlylet style: NSUnderlineStyle = [.thick, .patternDash, .byWord]
// Double solid underlinelet style: NSUnderlineStyle = [.double]
// Single dotted strikethroughlet attrs: [NSAttributedString.Key: Any] = [ .strikethroughStyle: NSUnderlineStyle.single.union(.patternDot).rawValue, .strikethroughColor: UIColor.red]NSShadow
Section titled “NSShadow”let shadow = NSShadow()shadow.shadowOffset = CGSize(width: 2, height: -2) // Right and upshadow.shadowBlurRadius = 4.0shadow.shadowColor = UIColor.black.withAlphaComponent(0.3)
let attrs: [NSAttributedString.Key: Any] = [.shadow: shadow]Note: SwiftUI Text ignores the .shadow attribute. Use .shadow() modifier instead (applies to entire view).
Text Effects
Section titled “Text Effects”// The only public text effectattrs[.textEffect] = NSAttributedString.TextEffectStyle.letterpressStyleLetterpress style: Embossed appearance with light source. Purely visual. Only one public effect exists.
NSParagraphStyle (Complete)
Section titled “NSParagraphStyle (Complete)”All Properties
Section titled “All Properties”let style = NSMutableParagraphStyle()
// Alignmentstyle.alignment = .natural // .left, .right, .center, .justified, .natural
// Line Spacingstyle.lineSpacing = 4 // Extra space between lines (after leading)style.minimumLineHeight = 20 // Floor for line heightstyle.maximumLineHeight = 30 // Ceiling for line heightstyle.lineHeightMultiple = 1.2 // Multiplier on natural line height
// Paragraph Spacingstyle.paragraphSpacing = 12 // Space AFTER paragraphstyle.paragraphSpacingBefore = 8 // Space BEFORE paragraph
// Indentationstyle.firstLineHeadIndent = 20 // First line indentstyle.headIndent = 10 // Subsequent lines indentstyle.tailIndent = -10 // Trailing margin (negative = from right edge)
// Line Breakingstyle.lineBreakMode = .byWordWrapping // .byCharWrapping, .byClipping, // .byTruncatingHead/Tail/Middlestyle.lineBreakStrategy = .standard // .pushOut, .hangulWordPriority
// Hyphenationstyle.hyphenationFactor = 0.5 // 0.0 (none) to 1.0 (max)style.usesDefaultHyphenation = true // iOS 15+ (system-determined)
// Writing Directionstyle.baseWritingDirection = .natural // .leftToRight, .rightToLeft
// Tabsstyle.tabStops = [ NSTextTab(textAlignment: .left, location: 100), NSTextTab(textAlignment: .decimal, location: 200),]style.defaultTabInterval = 36
// Tighteningstyle.allowsDefaultTighteningForTruncation = true // Reduce spacing before truncating
// Lists (AppKit + UIKit iOS 16+)style.textLists = [NSTextList(markerFormat: .disc, options: 0)]NSTextList Marker Formats
Section titled “NSTextList Marker Formats”| Format | Example | Platform |
|---|---|---|
.disc | • | All |
.circle | ○ | All |
.square | ■ | All |
.decimal | 1. 2. 3. | All |
.lowercaseAlpha | a. b. c. | All |
.uppercaseAlpha | A. B. C. | All |
.lowercaseRoman | i. ii. iii. | All |
.uppercaseRoman | I. II. III. | All |
.lowercaseLatin | a. b. c. | macOS |
.uppercaseLatin | A. B. C. | macOS |
.lowercaseHexadecimal | 1. 2. … a. b. | macOS |
.uppercaseHexadecimal | 1. 2. … A. B. | macOS |
.octal | 1. 2. … 10. | macOS |
.hyphen | - | macOS |
.check | ✓ | macOS |
NSTextTable / NSTextTableBlock (AppKit Only)
Section titled “NSTextTable / NSTextTableBlock (AppKit Only)”let table = NSTextTable()table.numberOfColumns = 3table.collapsesBorders = true
let cell = NSTextTableBlock( table: table, startingRow: 0, rowSpan: 1, startingColumn: 0, columnSpan: 1)cell.backgroundColor = .secondarySystemBackgroundcell.setWidth(1.0, type: .absoluteValueType, for: .border)cell.setWidth(4.0, type: .absoluteValueType, for: .padding)
let style = NSMutableParagraphStyle()style.textBlocks = [cell]
// Apply to the paragraph's attributed stringTriggers TextKit 1 fallback. No UIKit equivalent.
Stroke Width Trick
Section titled “Stroke Width Trick”Negative stroke width creates fill + stroke (outlined text):
// Outlined text (stroke only)attrs[.strokeWidth] = 3.0attrs[.strokeColor] = UIColor.blue
// Filled + outlined (negative width)attrs[.strokeWidth] = -3.0attrs[.strokeColor] = UIColor.blueattrs[.foregroundColor] = UIColor.whiteWhere Formatting Works
Section titled “Where Formatting Works”| Attribute | SwiftUI Text | TextEditor (iOS 26+) | UITextView | UILabel | NSTextView |
|---|---|---|---|---|---|
| font | ✅ | ✅ | ✅ | ✅ | ✅ |
| foregroundColor | ✅ | ✅ | ✅ | ✅ | ✅ |
| backgroundColor | ✅ | ✅ | ✅ | ✅ | ✅ |
| paragraphStyle | ❌ | ✅ (alignment, lineHeight) | ✅ | ✅ | ✅ |
| kern/tracking | ✅ | ✅ | ✅ | ✅ | ✅ |
| underlineStyle | ✅ | ✅ | ✅ | ✅ | ✅ |
| strikethroughStyle | ✅ | ✅ | ✅ | ✅ | ✅ |
| shadow | ❌ | ❌ | ✅ | ✅ | ✅ |
| strokeColor/Width | ❌ | ❌ | ✅ | ✅ | ✅ |
| link | ✅ | ✅ | ✅ | ❌ | ✅ |
| attachment | ❌ | ❌ | ✅ | ✅ (display) | ✅ |
| baselineOffset | ✅ | ✅ | ✅ | ✅ | ✅ |
| obliqueness | ❌ | ❌ | ✅ | ✅ | ✅ |
| expansion | ❌ | ❌ | ✅ | ✅ | ✅ |
| textEffect | ❌ | ❌ | ✅ | ✅ | ✅ |
| superscript | N/A | N/A | N/A | N/A | ✅ (AppKit) |
| toolTip | N/A | N/A | N/A | N/A | ✅ (AppKit) |
| textTable | N/A | N/A | N/A | N/A | ✅ (AppKit, TK1) |
| textList | ❌ | ❌ | ✅ (iOS 17+) | ✅ | ✅ |
UITextView Built-in Formatting UI
Section titled “UITextView Built-in Formatting UI”textView.allowsEditingTextAttributes = trueWhen enabled, the text selection menu shows a BIU button:
- B — Bold (toggles font weight)
- I — Italic (toggles font style)
- U — Underline (toggles underline style)
That’s the only built-in formatting UI. For more (font size, color, alignment), you must build custom UI.
RTF Round-Trip
Section titled “RTF Round-Trip”Attributes that survive RTF archiving:
- font, foregroundColor, backgroundColor, paragraphStyle
- underline, strikethrough, kern, baselineOffset
- link, attachment, shadow, strokeColor/Width
- superscript (AppKit), textList, textTable
Attributes that are lost in RTF:
- obliqueness, expansion (stored as font descriptors — may survive if font supports)
- textEffect (letterpress)
- custom attributes (unless you handle RTF custom tags)
Common Pitfalls
Section titled “Common Pitfalls”- Negative strokeWidth is fill+stroke, positive is stroke only — counterintuitive but important for outlined text.
- NSMutableParagraphStyle is required for changes — NSParagraphStyle is immutable. Always create mutable variant.
- paragraphStyle applies to entire paragraph — Even if you set it on a sub-range,
fixAttributesextends it to the full paragraph. - SwiftUI Text ignores most attributes — Only ~10 work. The rest are silently dropped.
- NSTextTable triggers TK1 fallback — AppKit-only, and forces TextKit 1 mode.
- kern vs tracking — Kern is absolute (points). Tracking scales with font size. Use tracking for proportional spacing.
Documentation Scope
Section titled “Documentation Scope”This page documents the apple-text-formatting-ref reference skill. Use it when the subsystem is already known and you need mechanics, behavior, or API detail.
Related
Section titled “Related”apple-text-attributed-string: Use when choosing between AttributedString and NSAttributedString, defining custom attributes, or converting between them.apple-text-colors: Use when choosing text colors, semantic colors, dark mode adaptation, or wide-color/HDR text across UIKit, AppKit, and SwiftUI.apple-text-attachments-ref: Use when embedding images, custom views, Genmoji, or other non-text content inline — NSTextAttachment, view providers, bounds, baseline.
Full SKILL.md source
---name: apple-text-formatting-refdescription: Use when looking up NSAttributedString.Key values, underline styles, shadows, lists, tables, or view-compatibility ruleslicense: MIT---
# Text Formatting Reference
Use this skill when you already know the formatting problem and need the exact attribute or compatibility rules.
## When to Use
- You need an `NSAttributedString.Key` reference.- You are checking which formatting works in which view.- You need paragraph-style, underline, shadow, or table-formatting details.
## Quick Decision
- Need type choice or custom attribute scopes -> `/skill apple-text-attributed-string`- Need exact formatting keys and compatibility -> stay here- Need semantic text colors rather than general formatting -> `/skill apple-text-colors`
## Core Guidance
## Character-Level Attributes (NSAttributedString.Key)
### Typography
| Key | Value Type | Effect | Min OS ||-----|-----------|--------|--------|| `.font` | UIFont / NSFont | Typeface, size, weight | All || `.kern` | NSNumber (CGFloat) | Inter-character spacing (points) | All || `.tracking` | NSNumber (CGFloat) | Tracking (scales with font size) | iOS 14+ || `.ligature` | NSNumber (Int) | 0=none, 1=default, 2=all (macOS only) | All || `.baselineOffset` | NSNumber (CGFloat) | Vertical shift from baseline | All || `.obliqueness` | NSNumber (CGFloat) | Synthetic italic (0=none, positive=right lean) | All || `.expansion` | NSNumber (CGFloat) | Horizontal stretch (0=normal, positive=wider) | All || `.verticalGlyphForm` | NSNumber (Int) | 0=horizontal, 1=vertical (CJK) | All |
### Color
| Key | Value Type | Effect | Min OS ||-----|-----------|--------|--------|| `.foregroundColor` | UIColor / NSColor | Text color | All || `.backgroundColor` | UIColor / NSColor | Background behind text | All || `.strokeColor` | UIColor / NSColor | Text outline color | All || `.strokeWidth` | NSNumber (CGFloat) | Outline width. Negative = fill + stroke | All || `.shadow` | NSShadow | Drop shadow | All |
### Decoration
| Key | Value Type | Effect | Min OS ||-----|-----------|--------|--------|| `.underlineStyle` | NSNumber (NSUnderlineStyle) | Underline pattern | All || `.underlineColor` | UIColor / NSColor | Underline color (nil = foreground color) | All || `.strikethroughStyle` | NSNumber (NSUnderlineStyle) | Strikethrough pattern | All || `.strikethroughColor` | UIColor / NSColor | Strikethrough color | All |
### Layout & Structure
| Key | Value Type | Effect | Min OS ||-----|-----------|--------|--------|| `.paragraphStyle` | NSParagraphStyle | Paragraph formatting (see below) | All || `.writingDirection` | [NSNumber] | Embedding/override direction | All || `.textEffect` | NSAttributedString.TextEffectStyle | Visual effect | iOS 7+ |
### Content
| Key | Value Type | Effect | Min OS ||-----|-----------|--------|--------|| `.attachment` | NSTextAttachment | Inline image/view | All || `.link` | URL or String | Hyperlink | All || `.textAlternatives` | NSTextAlternatives | Alternative text interpretations | iOS 18+ || `.adaptiveImageGlyph` | NSAdaptiveImageGlyph | Genmoji/stickers | iOS 18+ |
### AppKit-Only
| Key | Value Type | Effect ||-----|-----------|--------|| `.superscript` | NSNumber (Int) | Superscript (positive) or subscript (negative) || `.cursor` | NSCursor | Mouse cursor when hovering || `.toolTip` | String | Hover tooltip || `.markedClauseSegment` | NSNumber (Int) | CJK input clause segment || `.spellingState` | NSNumber (Int) | Spelling/grammar error indicator || `.glyphInfo` | NSGlyphInfo | Glyph substitution || `.textBlock` | NSTextBlock | Text block (table cell, etc.) |
## NSUnderlineStyle
Combine with bitwise OR for compound styles:
### Line Style
| Style | Visual ||-------|--------|| `.single` | Single line || `.thick` | Thick line || `.double` | Double line |
### Pattern (Combine with style)
| Pattern | Visual ||---------|--------|| (none) | Solid line || `.patternDot` | Dotted || `.patternDash` | Dashed || `.patternDashDot` | Dash-dot || `.patternDashDotDot` | Dash-dot-dot |
### Modifier
| Modifier | Effect ||----------|--------|| `.byWord` | Only under words, not spaces |
### Examples
```swift// Thick dashed underline, words onlylet style: NSUnderlineStyle = [.thick, .patternDash, .byWord]
// Double solid underlinelet style: NSUnderlineStyle = [.double]
// Single dotted strikethroughlet attrs: [NSAttributedString.Key: Any] = [ .strikethroughStyle: NSUnderlineStyle.single.union(.patternDot).rawValue, .strikethroughColor: UIColor.red]```
## NSShadow
```swiftlet shadow = NSShadow()shadow.shadowOffset = CGSize(width: 2, height: -2) // Right and upshadow.shadowBlurRadius = 4.0shadow.shadowColor = UIColor.black.withAlphaComponent(0.3)
let attrs: [NSAttributedString.Key: Any] = [.shadow: shadow]```
**Note:** SwiftUI Text ignores the `.shadow` attribute. Use `.shadow()` modifier instead (applies to entire view).
## Text Effects
```swift// The only public text effectattrs[.textEffect] = NSAttributedString.TextEffectStyle.letterpressStyle```
**Letterpress style:** Embossed appearance with light source. Purely visual. Only one public effect exists.
## NSParagraphStyle (Complete)
### All Properties
```swiftlet style = NSMutableParagraphStyle()
// Alignmentstyle.alignment = .natural // .left, .right, .center, .justified, .natural
// Line Spacingstyle.lineSpacing = 4 // Extra space between lines (after leading)style.minimumLineHeight = 20 // Floor for line heightstyle.maximumLineHeight = 30 // Ceiling for line heightstyle.lineHeightMultiple = 1.2 // Multiplier on natural line height
// Paragraph Spacingstyle.paragraphSpacing = 12 // Space AFTER paragraphstyle.paragraphSpacingBefore = 8 // Space BEFORE paragraph
// Indentationstyle.firstLineHeadIndent = 20 // First line indentstyle.headIndent = 10 // Subsequent lines indentstyle.tailIndent = -10 // Trailing margin (negative = from right edge)
// Line Breakingstyle.lineBreakMode = .byWordWrapping // .byCharWrapping, .byClipping, // .byTruncatingHead/Tail/Middlestyle.lineBreakStrategy = .standard // .pushOut, .hangulWordPriority
// Hyphenationstyle.hyphenationFactor = 0.5 // 0.0 (none) to 1.0 (max)style.usesDefaultHyphenation = true // iOS 15+ (system-determined)
// Writing Directionstyle.baseWritingDirection = .natural // .leftToRight, .rightToLeft
// Tabsstyle.tabStops = [ NSTextTab(textAlignment: .left, location: 100), NSTextTab(textAlignment: .decimal, location: 200),]style.defaultTabInterval = 36
// Tighteningstyle.allowsDefaultTighteningForTruncation = true // Reduce spacing before truncating
// Lists (AppKit + UIKit iOS 16+)style.textLists = [NSTextList(markerFormat: .disc, options: 0)]```
### NSTextList Marker Formats
| Format | Example | Platform ||--------|---------|----------|| `.disc` | • | All || `.circle` | ○ | All || `.square` | ■ | All || `.decimal` | 1. 2. 3. | All || `.lowercaseAlpha` | a. b. c. | All || `.uppercaseAlpha` | A. B. C. | All || `.lowercaseRoman` | i. ii. iii. | All || `.uppercaseRoman` | I. II. III. | All || `.lowercaseLatin` | a. b. c. | macOS || `.uppercaseLatin` | A. B. C. | macOS || `.lowercaseHexadecimal` | 1. 2. ... a. b. | macOS || `.uppercaseHexadecimal` | 1. 2. ... A. B. | macOS || `.octal` | 1. 2. ... 10. | macOS || `.hyphen` | - | macOS || `.check` | ✓ | macOS |
### NSTextTable / NSTextTableBlock (AppKit Only)
```swiftlet table = NSTextTable()table.numberOfColumns = 3table.collapsesBorders = true
let cell = NSTextTableBlock( table: table, startingRow: 0, rowSpan: 1, startingColumn: 0, columnSpan: 1)cell.backgroundColor = .secondarySystemBackgroundcell.setWidth(1.0, type: .absoluteValueType, for: .border)cell.setWidth(4.0, type: .absoluteValueType, for: .padding)
let style = NSMutableParagraphStyle()style.textBlocks = [cell]
// Apply to the paragraph's attributed string```
**Triggers TextKit 1 fallback.** No UIKit equivalent.
## Stroke Width Trick
Negative stroke width creates fill + stroke (outlined text):
```swift// Outlined text (stroke only)attrs[.strokeWidth] = 3.0attrs[.strokeColor] = UIColor.blue
// Filled + outlined (negative width)attrs[.strokeWidth] = -3.0attrs[.strokeColor] = UIColor.blueattrs[.foregroundColor] = UIColor.white```
## Where Formatting Works
| Attribute | SwiftUI Text | TextEditor (iOS 26+) | UITextView | UILabel | NSTextView ||-----------|-------------|---------------------|------------|---------|------------|| font | ✅ | ✅ | ✅ | ✅ | ✅ || foregroundColor | ✅ | ✅ | ✅ | ✅ | ✅ || backgroundColor | ✅ | ✅ | ✅ | ✅ | ✅ || paragraphStyle | ❌ | ✅ (alignment, lineHeight) | ✅ | ✅ | ✅ || kern/tracking | ✅ | ✅ | ✅ | ✅ | ✅ || underlineStyle | ✅ | ✅ | ✅ | ✅ | ✅ || strikethroughStyle | ✅ | ✅ | ✅ | ✅ | ✅ || shadow | ❌ | ❌ | ✅ | ✅ | ✅ || strokeColor/Width | ❌ | ❌ | ✅ | ✅ | ✅ || link | ✅ | ✅ | ✅ | ❌ | ✅ || attachment | ❌ | ❌ | ✅ | ✅ (display) | ✅ || baselineOffset | ✅ | ✅ | ✅ | ✅ | ✅ || obliqueness | ❌ | ❌ | ✅ | ✅ | ✅ || expansion | ❌ | ❌ | ✅ | ✅ | ✅ || textEffect | ❌ | ❌ | ✅ | ✅ | ✅ || superscript | N/A | N/A | N/A | N/A | ✅ (AppKit) || toolTip | N/A | N/A | N/A | N/A | ✅ (AppKit) || textTable | N/A | N/A | N/A | N/A | ✅ (AppKit, TK1) || textList | ❌ | ❌ | ✅ (iOS 17+) | ✅ | ✅ |
## UITextView Built-in Formatting UI
```swifttextView.allowsEditingTextAttributes = true```
When enabled, the text selection menu shows a **BIU** button:- **B** — Bold (toggles font weight)- **I** — Italic (toggles font style)- **U** — Underline (toggles underline style)
That's the only built-in formatting UI. For more (font size, color, alignment), you must build custom UI.
## RTF Round-Trip
Attributes that **survive** RTF archiving:- font, foregroundColor, backgroundColor, paragraphStyle- underline, strikethrough, kern, baselineOffset- link, attachment, shadow, strokeColor/Width- superscript (AppKit), textList, textTable
Attributes that are **lost** in RTF:- obliqueness, expansion (stored as font descriptors — may survive if font supports)- textEffect (letterpress)- custom attributes (unless you handle RTF custom tags)
## Common Pitfalls
1. **Negative strokeWidth is fill+stroke, positive is stroke only** — counterintuitive but important for outlined text.2. **NSMutableParagraphStyle is required for changes** — NSParagraphStyle is immutable. Always create mutable variant.3. **paragraphStyle applies to entire paragraph** — Even if you set it on a sub-range, `fixAttributes` extends it to the full paragraph.4. **SwiftUI Text ignores most attributes** — Only ~10 work. The rest are silently dropped.5. **NSTextTable triggers TK1 fallback** — AppKit-only, and forces TextKit 1 mode.6. **kern vs tracking** — Kern is absolute (points). Tracking scales with font size. Use tracking for proportional spacing.
## Related Skills
- Use `/skill apple-text-attributed-string` for AttributedString vs NSAttributedString decisions.- Use `/skill apple-text-colors` when the formatting question is mostly about semantic color behavior.- Use `/skill apple-text-attachments-ref` for inline non-text content instead of pure formatting attributes.