agentsclimarketplace

Dynamic type scaling

Skill almasumdev/awesome-mobile-accessibility-agent-skills/.github/skills/visual/dynamic-type-scaling

Honoring user font-scale preferences on iOS, Android (Views and Compose), Flutter, and React Native. Use this when building text-heavy screens or component libraries.From its SKILL.md

Install
npx -y skills add almasumdev/awesome-mobile-accessibility-agent-skills --skill dynamic-type-scaling

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

5.2 KB, ~1.3k tokens by cl100k_base, as published. Nobody here has run it

Dynamic Type and Font Scaling

Instructions

Users can set their system font 1.5–2x larger than default. Apps that clamp or ignore this scale are the #1 source of real-world accessibility complaints.

1. iOS — Dynamic Type

Use text styles, not point sizes.

UIKit:

let label = UILabel()
label.font = UIFont.preferredFont(forTextStyle: .body)
label.adjustsFontForContentSizeCategory = true
label.numberOfLines = 0

SwiftUI:

Text("Welcome")
    .font(.title2)
    .dynamicTypeSize(.small ... .accessibility5) // cap only if truly necessary
  • Prefer .body, .headline, .callout, .footnote over .system(size:).
  • adjustsFontForContentSizeCategory = true on every label, text field, button title.
  • Use UIFontMetrics(forTextStyle:).scaledValue(for:) for layout metrics that should scale too (icon size, row height).

2. Android Views — sp

  • All text sizes in sp (scale-independent pixels), all other dimensions in dp.
  • Never use px for text. Never use dp for text except inside a WebView or Canvas where scaling is applied manually.
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/welcome"
    android:textAppearance="?attr/textAppearanceBodyLarge" />
  • Prefer Material type scale (?attr/textAppearanceBodyLarge, titleMedium, etc.) so sizes come from the theme.

3. Jetpack Compose — fontScale

Compose text already scales with LocalDensity.fontScale. Don't fight it.

Text(
    text = "Welcome",
    style = MaterialTheme.typography.titleLarge,
)

If you accept a TextUnit, use sp:

Text("Subtitle", fontSize = 14.sp) // NOT .dp

To test different scales:

CompositionLocalProvider(LocalDensity provides Density(
    density = LocalDensity.current.density,
    fontScale = 1.5f
)) { App() }

Preview helper:

@Preview(fontScale = 1.5f, showBackground = true)
@Composable fun PreviewLargeFont() { /* ... */ }

4. Flutter — TextScaler

Flutter 3.16+ uses TextScaler (replacing deprecated textScaleFactor).

final scaler = MediaQuery.textScalerOf(context);
final scaled = scaler.scale(16.0); // use for icon sizes, row heights

Text(
  'Welcome',
  style: Theme.of(context).textTheme.titleLarge, // scales automatically
)

Never force TextScaler.linear(1.0) globally. If you must clamp:

MediaQuery(
  data: MediaQuery.of(context).copyWith(
    textScaler: MediaQuery.textScalerOf(context)
        .clamp(minScaleFactor: 1.0, maxScaleFactor: 1.8),
  ),
  child: child,
)

Wrap long strings in Flexible/Expanded so they wrap instead of overflow.

5. React Native — allowFontScaling

Default is true — keep it.

<Text style={{ fontSize: 16, lineHeight: 22 }}>
  Welcome
</Text>

Never do:

<Text allowFontScaling={false}>Welcome</Text>   // BAD globally
Text.defaultProps = { allowFontScaling: false } // BAD globally

If you must cap (e.g., for pixel-perfect brand headers):

<Text maxFontSizeMultiplier={1.8}>Brand headline</Text>

For icons inside buttons, scale manually using PixelRatio.getFontScale():

import { PixelRatio } from 'react-native';
const iconSize = 20 * Math.min(PixelRatio.getFontScale(), 1.8);

6. Layout Rules for Scalable Text

  • Never fix a text container's height in dp/pt/px. Use wrap_content / intrinsic size.
  • Use minimumScaleFactor sparingly — shrinking text fails WCAG 1.4.4.
  • Prefer vertical stacking over horizontal for label-value pairs when font scale > 1.3.
  • Truncating is acceptable only for preview text that has a "see more" affordance.

7. Testing Large Sizes

  • iOS Simulator: Features → Toggle Accessibility Inspector → Dynamic Type slider; or Settings → Accessibility → Display & Text Size → Larger Text.
  • Android Emulator: Settings → Display → Display size and text → Font size (largest). Also test Display size (density scaling).
  • Flutter: wrap root with MediaQuery(..., textScaler: TextScaler.linear(2.0)) in a debug build.
  • RN: enable system large text; also write Jest snapshot with PixelRatio mocked.

8. Common Pitfalls

  • Clamping font scale to 1.0 "because the design breaks". Fix the design.
  • Using fontSize for numerical metrics (avatar diameter) — use text-style-relative sizing.
  • SingleLine = true on labels that contain translated content — truncation.
  • Hard-coded row heights in lists; switch to intrinsic + padding.
  • Passing dp or px to a TextView via code.

Checklist

  • All text uses scaled units (sp, .preferredFont, TextScaler, RN default).
  • No allowFontScaling={false} globally; caps justified per-case.
  • Screens tested at largest accessible Dynamic Type / font scale.
  • Icons and row heights scale proportionally where appropriate.
  • No horizontal clipping / truncation of essential content at 200%.
  • Previews / snapshots exist at an enlarged font scale (1.5x+).

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.