apple-text-formatting-ref

Use when looking up NSAttributedString.Key values, underline styles, shadows, lists, tables, or view-compatibility rules

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

KeyValue TypeEffectMin OS
.fontUIFont / NSFontTypeface, size, weightAll
.kernNSNumber (CGFloat)Inter-character spacing (points)All
.trackingNSNumber (CGFloat)Tracking (scales with font size)iOS 14+
.ligatureNSNumber (Int)0=none, 1=default, 2=all (macOS only)All
.baselineOffsetNSNumber (CGFloat)Vertical shift from baselineAll
.obliquenessNSNumber (CGFloat)Synthetic italic (0=none, positive=right lean)All
.expansionNSNumber (CGFloat)Horizontal stretch (0=normal, positive=wider)All
.verticalGlyphFormNSNumber (Int)0=horizontal, 1=vertical (CJK)All

Color

KeyValue TypeEffectMin OS
.foregroundColorUIColor / NSColorText colorAll
.backgroundColorUIColor / NSColorBackground behind textAll
.strokeColorUIColor / NSColorText outline colorAll
.strokeWidthNSNumber (CGFloat)Outline width. Negative = fill + strokeAll
.shadowNSShadowDrop shadowAll

Decoration

KeyValue TypeEffectMin OS
.underlineStyleNSNumber (NSUnderlineStyle)Underline patternAll
.underlineColorUIColor / NSColorUnderline color (nil = foreground color)All
.strikethroughStyleNSNumber (NSUnderlineStyle)Strikethrough patternAll
.strikethroughColorUIColor / NSColorStrikethrough colorAll

Layout & Structure

KeyValue TypeEffectMin OS
.paragraphStyleNSParagraphStyleParagraph formatting (see below)All
.writingDirection[NSNumber]Embedding/override directionAll
.textEffectNSAttributedString.TextEffectStyleVisual effectiOS 7+

Content

KeyValue TypeEffectMin OS
.attachmentNSTextAttachmentInline image/viewAll
.linkURL or StringHyperlinkAll
.textAlternativesNSTextAlternativesAlternative text interpretationsiOS 18+
.adaptiveImageGlyphNSAdaptiveImageGlyphGenmoji/stickersiOS 18+

AppKit-Only

KeyValue TypeEffect
.superscriptNSNumber (Int)Superscript (positive) or subscript (negative)
.cursorNSCursorMouse cursor when hovering
.toolTipStringHover tooltip
.markedClauseSegmentNSNumber (Int)CJK input clause segment
.spellingStateNSNumber (Int)Spelling/grammar error indicator
.glyphInfoNSGlyphInfoGlyph substitution
.textBlockNSTextBlockText block (table cell, etc.)

NSUnderlineStyle

Combine with bitwise OR for compound styles:

Line Style

StyleVisual
.singleSingle line
.thickThick line
.doubleDouble line

Pattern (Combine with style)

PatternVisual
(none)Solid line
.patternDotDotted
.patternDashDashed
.patternDashDotDash-dot
.patternDashDotDotDash-dot-dot

Modifier

ModifierEffect
.byWordOnly under words, not spaces

Examples

// Thick dashed underline, words only
let style: NSUnderlineStyle = [.thick, .patternDash, .byWord]

// Double solid underline
let style: NSUnderlineStyle = [.double]

// Single dotted strikethrough
let attrs: [NSAttributedString.Key: Any] = [
    .strikethroughStyle: NSUnderlineStyle.single.union(.patternDot).rawValue,
    .strikethroughColor: UIColor.red
]

NSShadow

let shadow = NSShadow()
shadow.shadowOffset = CGSize(width: 2, height: -2) // Right and up
shadow.shadowBlurRadius = 4.0
shadow.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

// The only public text effect
attrs[.textEffect] = NSAttributedString.TextEffectStyle.letterpressStyle

Letterpress style: Embossed appearance with light source. Purely visual. Only one public effect exists.

NSParagraphStyle (Complete)

All Properties

let style = NSMutableParagraphStyle()

// Alignment
style.alignment = .natural          // .left, .right, .center, .justified, .natural

// Line Spacing
style.lineSpacing = 4               // Extra space between lines (after leading)
style.minimumLineHeight = 20        // Floor for line height
style.maximumLineHeight = 30        // Ceiling for line height
style.lineHeightMultiple = 1.2      // Multiplier on natural line height

// Paragraph Spacing
style.paragraphSpacing = 12         // Space AFTER paragraph
style.paragraphSpacingBefore = 8    // Space BEFORE paragraph

// Indentation
style.firstLineHeadIndent = 20      // First line indent
style.headIndent = 10               // Subsequent lines indent
style.tailIndent = -10              // Trailing margin (negative = from right edge)

// Line Breaking
style.lineBreakMode = .byWordWrapping    // .byCharWrapping, .byClipping,
                                          // .byTruncatingHead/Tail/Middle
style.lineBreakStrategy = .standard      // .pushOut, .hangulWordPriority

// Hyphenation
style.hyphenationFactor = 0.5       // 0.0 (none) to 1.0 (max)
style.usesDefaultHyphenation = true // iOS 15+ (system-determined)

// Writing Direction
style.baseWritingDirection = .natural  // .leftToRight, .rightToLeft

// Tabs
style.tabStops = [
    NSTextTab(textAlignment: .left, location: 100),
    NSTextTab(textAlignment: .decimal, location: 200),
]
style.defaultTabInterval = 36

// Tightening
style.allowsDefaultTighteningForTruncation = true // Reduce spacing before truncating

// Lists (AppKit + UIKit iOS 16+)
style.textLists = [NSTextList(markerFormat: .disc, options: 0)]

NSTextList Marker Formats

FormatExamplePlatform
.discAll
.circleAll
.squareAll
.decimal1. 2. 3.All
.lowercaseAlphaa. b. c.All
.uppercaseAlphaA. B. C.All
.lowercaseRomani. ii. iii.All
.uppercaseRomanI. II. III.All
.lowercaseLatina. b. c.macOS
.uppercaseLatinA. B. C.macOS
.lowercaseHexadecimal1. 2. ... a. b.macOS
.uppercaseHexadecimal1. 2. ... A. B.macOS
.octal1. 2. ... 10.macOS
.hyphen-macOS
.checkmacOS

NSTextTable / NSTextTableBlock (AppKit Only)

let table = NSTextTable()
table.numberOfColumns = 3
table.collapsesBorders = true

let cell = NSTextTableBlock(
    table: table,
    startingRow: 0, rowSpan: 1,
    startingColumn: 0, columnSpan: 1
)
cell.backgroundColor = .secondarySystemBackground
cell.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):

// Outlined text (stroke only)
attrs[.strokeWidth] = 3.0
attrs[.strokeColor] = UIColor.blue

// Filled + outlined (negative width)
attrs[.strokeWidth] = -3.0
attrs[.strokeColor] = UIColor.blue
attrs[.foregroundColor] = UIColor.white

Where Formatting Works

AttributeSwiftUI TextTextEditor (iOS 26+)UITextViewUILabelNSTextView
font
foregroundColor
backgroundColor
paragraphStyle✅ (alignment, lineHeight)
kern/tracking
underlineStyle
strikethroughStyle
shadow
strokeColor/Width
link
attachment✅ (display)
baselineOffset
obliqueness
expansion
textEffect
superscriptN/AN/AN/AN/A✅ (AppKit)
toolTipN/AN/AN/AN/A✅ (AppKit)
textTableN/AN/AN/AN/A✅ (AppKit, TK1)
textList✅ (iOS 17+)

UITextView Built-in Formatting UI

textView.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.