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
npx -y skills add almasumdev/awesome-mobile-accessibility-agent-skills --skill dynamic-type-scalingAssembled 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,.footnoteover.system(size:). adjustsFontForContentSizeCategory = trueon 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 indp. - Never use
pxfor text. Never usedpfor 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. Usewrap_content/ intrinsic size. - Use
minimumScaleFactorsparingly — 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
PixelRatiomocked.
8. Common Pitfalls
- Clamping font scale to 1.0 "because the design breaks". Fix the design.
- Using
fontSizefor numerical metrics (avatar diameter) — use text-style-relative sizing. SingleLine = trueon labels that contain translated content — truncation.- Hard-coded row heights in lists; switch to intrinsic +
padding. - Passing
dporpxto aTextViewvia 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.