Escala de Tipografia e Carregamento de Fontes
expo-font, famílias personalizadas e dimensionamento de texto acessível.
Busque em todas as páginas da documentação
expo-font, famílias personalizadas e dimensionamento de texto acessível.
Cartão de receita de referência rápida - pronto para copiar e colar.
npx expo install expo-font expo-splash-screen// app/_layout.tsx (raiz do Expo Router) ou App.tsx
import { useFonts } from "expo-font";
import * as SplashScreen from "expo-splash-screen";
import { useEffect } from "react";
import { Text, View } from "react-native";
import { typography } from "./theme/typography";
SplashScreen.preventAutoHideAsync();
export default function RootLayout() {
const [loaded, error] = useFonts({
"Inter-Regular": require("./assets/fonts/Inter-Regular.ttf"),
"Inter-SemiBold": require("./assets/fonts/Inter-SemiBold.ttf"),
});
useEffect(() => {
if (loaded || error) SplashScreen.hideAsync();
}, [loaded, error]);
if (!loaded && !error) return null;
return (
<View style={{ flex: 1 }}>
<Text style={typography.title}>Tipografia pronta</Text>
<Text style={typography.body}>Inter carrega antes da primeira pintura.</Text>
</View>
);
}// theme/typography.ts
import { StyleSheet } from "react-native";
export const typography = StyleSheet.create({
title: {
fontFamily: "Inter-SemiBold",
fontSize: 24,
lineHeight: 32,
letterSpacing: -0.3,
color: "#0f172a",
},
body: {
fontFamily: "Inter-Regular",
fontSize: 16,
lineHeight: 24,
color: "#334155",
},
caption: {
fontFamily: "Inter-Regular",
fontSize: 12,
lineHeight: 16,
color: "#64748b",
},
});Quando usar isso: Fontes de marca, hierarquia de títulos consistente ou texto seguro para acessibilidade - você precisa de famílias personalizadas carregadas antes que a UI seja renderizada e uma escala de tokens em vez de números mágicos espalhados pelas telas.
import { useFonts } from "expo-font";
import * as SplashScreen from "expo-splash-screen";
import { useEffect } from "react";
import { PixelRatio, StyleSheet, Text, View } from "react-native";
SplashScreen.preventAutoHideAsync();
const FONT_SCALE = PixelRatio.getFontScale();
type TextVariant = "display" | "title" | "body" | "caption" | "label";
const variantStyles: Record<TextVariant, object> = {
display: typography.display,
title: typography.title,
body: typography.body,
caption: typography.caption,
label: typography.label,
};
function AppText({
variant = "body",
children,
maxScale = 1.35,
}: {
variant?: TextVariant;
children: React.ReactNode;
maxScale?: number;
}) {
return (
<Text
style={variantStyles[variant]}
allowFontScaling
maxFontSizeMultiplier={maxScale}
>
{children}
</Text>
);
}
export default function TypographyScreen() {
const [fontsLoaded, fontError] = useFonts({
"Inter-Regular": require("./assets/fonts/Inter-Regular.ttf"),
"Inter-SemiBold": require("./assets/fonts/Inter-SemiBold.ttf"),
"Inter-Bold": require("./assets/fonts/Inter-Bold.ttf"),
});
useEffect(() => {
if (fontsLoaded || fontError) SplashScreen.hideAsync();
}, [fontsLoaded, fontError]);
if (!fontsLoaded && !fontError) return null;
return (
<View style={styles.screen}>
<AppText variant="display">Bom dia</AppText>
<AppText variant="title">Suas tarefas de hoje</AppText>
<AppText variant="body">
A escala de fonte do sistema é {FONT_SCALE.toFixed(2)}×. A cópia do corpo
escala com as configurações de acessibilidade até o limite configurado.
</AppText>
<AppText variant="caption">Última sincronização há 2 min</AppText>
<View style={styles.chip}>
<AppText variant="label" maxScale={1.2}>
3 atrasadas
</AppText>
</View>
</View>
);
}
const typography = StyleSheet.create({
display: {
fontFamily: "Inter-Bold",
fontSize: 34,
lineHeight: 40,
letterSpacing: -0.5,
color: "#0f172a",
},
title: {
fontFamily: "Inter-SemiBold",
fontSize: 22,
lineHeight: 28,
color: "#0f172a",
},
body: {
fontFamily: "Inter-Regular",
fontSize: 16,
lineHeight: 24,
color: "#334155",
},
caption: {
fontFamily: "Inter-Regular",
fontSize: 13,
lineHeight: 18,
color: "#64748b",
},
label: {
fontFamily: "Inter-SemiBold",
fontSize: 12,
lineHeight: 16,
letterSpacing: 0.6,
textTransform: "uppercase",
color: "#475569",
},
});
const styles = StyleSheet.create({
screen: { flex: 1, padding: 24, gap: 12, backgroundColor: "#f8fafc" },
chip: {
alignSelf: "flex-start",
marginTop: 8,
paddingHorizontal: 10,
paddingVertical: 4,
borderRadius: 6,
backgroundColor: "#fee2e2",
},
});O que isso demonstra:
useFonts carrega vários pesos como chaves de família separadas - o padrão do Expo SDK 57 para arquivos TTF estáticosdisplay, title, body, caption, label) centralizam tamanho, altura da linha e famíliaAppText aplica allowFontScaling e maxFontSizeMultiplier caps por variantePixelRatio.getFontScale() expõe o multiplicador de acessibilidade atual para depuração de layoutexpo-font é distribuído com o Expo SDK 57 e envolve o registro nativo de fontes no iOS e Android.
| API | Caso de uso |
|---|---|
useFonts(map) | Hook do React - retorna [loaded, error]; melhor para controle de layout raiz |
Font.loadAsync(map) | Pré-carregamento imperativo em rotinas de bootstrap junto com Asset.loadAsync |
Font.isLoaded(name) | Verifica uma única família antes de renderizar uma subárvore preguiçosa |
import * as Font from "expo-font";
// Lote imperativo (por exemplo, antes da montagem da navegação)
await Font.loadAsync({
"Inter-Regular": require("./assets/fonts/Inter-Regular.ttf"),
});Instale alinhado com o SDK 57:
npx expo install expo-font expo-splash-screenOs arquivos de fonte devem residir em assets/ e ser require()'d estaticamente - o Metro os agrupa no momento da compilação.
Sem um controle, o React renderiza imediatamente com a fonte do sistema, depois troca quando as fontes personalizadas chegam (flash de texto sem estilo).
import * as SplashScreen from "expo-splash-screen";
SplashScreen.preventAutoHideAsync();
// No componente raiz
useEffect(() => {
if (loaded || error) SplashScreen.hideAsync();
}, [loaded, error]);
if (!loaded && !error) return null;preventAutoHideAsync no escopo do módulo antes da primeira renderização.null (ou um placeholder mínimo) enquanto loaded for falso.React Native não mapeia fontWeight: "600" para um TTF personalizado automaticamente. Cada peso/estilo é geralmente um arquivo separado registrado sob seu próprio nome de família.
// Funciona - família explícita por arquivo
{ fontFamily: "Inter-SemiBold", fontSize: 18 }
// Não confiável com fontes personalizadas - pode voltar para o negrito do sistema
{ fontFamily: "Inter-Regular", fontWeight: "600", fontSize: 18 }| Abordagem | Prós | Contras |
|---|---|---|
Arquivos separados por peso (Inter-Bold, etc.) | Previsível no iOS e Android | Mais arquivos para carregar |
| Fonte variável única (quando suportada) | Um arquivo | Verifique o suporte do RN/Expo para o seu formato de fonte |
Fonte do sistema (fontFamily: undefined) | Zero tempo de carregamento, sensação nativa | Sem tipografia de marca |
Defina uma rampa fixa - não escolha fontSize por tela ad hoc.
| Token | fontSize / lineHeight Típico | Uso |
|---|---|---|
display | 32–40 / 38–48 | Títulos principais |
title | 20–24 / 26–32 | Títulos de tela, cabeçalhos de cartão |
body | 15–17 / 22–26 | Parágrafos, texto principal da lista |
caption | 11–13 / 14–18 | Carimbos de data/hora, metadados |
label | 11–12 / 14–16 | Chips, badges, overlines |
export const fontSize = {
xs: 12,
sm: 14,
md: 16,
lg: 20,
xl: 24,
"2xl": 32,
} as const;
// lineHeight ≈ 1.4–1.5 × fontSize para corpo; mais apertado para displayCombine tokens com letterSpacing e textTransform em rótulos - mantenha o ritmo numérico em um módulo.
iOS e Android expõem configurações de acessibilidade de escala de fonte. React Native as respeita por padrão em Text.
| Prop | Padrão | Propósito |
|---|---|---|
allowFontScaling | true | Quando false, ignora a escala de fonte do sistema |
maxFontSizeMultiplier | ilimitado | Limita o quão grande o texto pode crescer (iOS/Android) |
adjustsFontSizeToFit | false | Diminui o texto para caber na caixa numberOfLines (iOS) |
<Text allowFontScaling maxFontSizeMultiplier={1.3} style={typography.body}>
Texto de corpo acessível
</Text>
// UI Densa - barra de ferramentas, rótulos de aba
<Text maxFontSizeMultiplier={1.1} numberOfLines={1}>
Painel
</Text>Use PixelRatio.getFontScale() para registrar ou adaptar layouts em escalas extremas (por exemplo, alternar linhas de lista para duas linhas).
Não desative allowFontScaling em todo o aplicativo - isso quebra a acessibilidade. Limite seletivamente em chips, barras de navegação e botões de altura fixa.
lineHeight está em pixels independentes de densidade, não sem unidade como line-height: 1.5 do CSS.lineHeight = fontSize × 1.4 para corpo, mais apertado para tipos de exibição grandes.Text dentro de uma linha com alignItems: "center" pode parecer estranho se as alturas das linhas diferirem - normalize as variantes.body: {
fontSize: 16,
lineHeight: 24, // 1.5× - parágrafo confortável
},
display: {
fontSize: 34,
lineHeight: 40, // ~1.18× - herói apertado
},Carregue fontes na mesma rotina de bootstrap que o pré-carregamento de imagens:
import { Asset } from "expo-asset";
import * as Font from "expo-font";
export async function loadResources() {
await Promise.all([
Asset.loadAsync([require("./assets/logo.png")]),
Font.loadAsync({
"Inter-Regular": require("./assets/fonts/Inter-Regular.ttf"),
}),
]);
}Veja o artigo sobre imagens e assets para coordenação de splash com Asset.loadAsync.
import type { TextStyle } from "react-native";
export type TypographyVariant = "display" | "title" | "body" | "caption";
export const typography: Record<TypographyVariant, TextStyle> = StyleSheet.create({
display: { fontFamily: "Inter-Bold", fontSize: 34, lineHeight: 40 },
title: { fontFamily: "Inter-SemiBold", fontSize: 22, lineHeight: 28 },
body: { fontFamily: "Inter-Regular", fontSize: 16, lineHeight: 24 },
caption: { fontFamily: "Inter-Regular", fontSize: 13, lineHeight: 18 },
});TextStyle inclui fontFamily, fontSize, lineHeight, letterSpacing, fontVariant.useFonts são strings - use a mesma string em fontFamily.require() de .ttf / .otf retorna um número (ID do módulo de asset) no momento da compilação.Flash de fonte do sistema - Renderização de texto antes que useFonts seja resolvido. Correção: Controle o layout raiz com a tela de apresentação + return null até que loaded.
fontWeight com família personalizada - fontFamily: "Inter" + fontWeight: "700" geralmente ignora o arquivo personalizado. Correção: Registre cada peso como seu próprio nome de família e referencie-o diretamente.
String de família de fonte incorreta - fontFamily deve corresponder exatamente à chave useFonts ("Inter-SemiBold", não "Inter SemiBold"). Correção: Copie as chaves do mapa de carregamento.
Arquivo de fonte ausente no pacote - Caminhos require() dinâmicos falham na análise estática do Metro. Correção: Apenas require("./assets/fonts/Inter-Regular.ttf") estático.
Escala sem limites quebra layouts - Fontes de acessibilidade grandes transbordam barras de ferramentas e chips. Correção: maxFontSizeMultiplier em componentes densos; permita a escala completa na cópia do corpo.
lineHeight muito pequeno - Descendentes são cortados no Android com alturas de linha apertadas. Correção: Aumente lineHeight ou adicione paddingVertical em badges de linha única.
Splash nunca esconde em erro de fonte - Esperando apenas por loaded. Correção: if (loaded || error) SplashScreen.hideAsync() e mostre uma UI de fallback com fonte do sistema.
Suposições de fonte variável - Nem todos os arquivos de fonte variável funcionam de forma idêntica entre plataformas. Correção: Teste em dispositivos iOS e Android; volte para pesos estáticos se os pesos não forem resolvidos.
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
Hook useFonts na raiz | Expo Router / layout raiz único | Fontes necessárias apenas em uma tela preguiçosa (ainda pré-carregue na raiz para consistência) |
Font.loadAsync no bootstrap | Carregador compartilhado com Asset.loadAsync | Você prefere controle de splash baseado em hook |
| Apenas fontes do sistema | Utilitários, ferramentas internas, envio mais rápido | Diretrizes de marca exigem tipografia personalizada |
Pacotes @expo-google-fonts/* | Fontes abertas populares sem agrupar arquivos | Fontes licenciadas corporativas não disponíveis no Google Fonts |
expo-google-fonts + useFonts | Configuração rápida de Inter/Roboto | Você já envia ativos OTF/TTF licenciados |
| Tokens de texto Tamagui / NativeWind | Sistema de design com tipografia temática | Uma tela com dois estilos de texto |
npx expo install expo-font expo-splash-screenexpo-font está incluído no Expo SDK - expo install fixa uma versão compatível.useFonts de expo-font no seu layout raiz..ttf ou .otf em assets/fonts/ e use require() estaticamente.useFonts é um hook do React que aciona a re-renderização quando o carregamento é concluído - ideal para árvores de componentes.Font.loadAsync retorna uma Promise - ideal para bootstrap imperativo antes de registerRootComponent.require().useFonts."Inter-Bold" em fontFamily, não "Inter" com fontWeight: "700".SplashScreen.preventAutoHideAsync();
// ...
if (!loaded && !error) return null;Text de marca até que loaded seja verdadeiro.fontSize e lineHeight emparelhados.theme/typography.ts como StyleSheet.create ou objetos simples.fontSize: 17.true para quase toda a cópia voltada para o usuário - respeita as configurações de acessibilidade.false apenas para texto decorativo ou ícones de tamanho fixo implementados como texto (raro).maxFontSizeMultiplier em vez de desativar a escala completamente.1.0 significa sem escala; 1.3 permite até 30% maior que o fontSize do estilo.1.5 ou superior.fontFamily.require().fontWeight em vez do arquivo de família correto - carregue e referencie cada peso explicitamente.lineHeight: 24 com fontSize: 16.fontSize; títulos de exibição: ~1.1–1.2×.lineHeight ou adicione paddingVertical.@expo-google-fonts/inter envolvem useFonts com assets pré-empacotados.npx expo install @expo-google-fonts/inter expo-font.require() local de arquivos OTF/TTF.numberOfLines, flexShrink: 1 e barras de ferramentas de várias linhas em escalas altas.PixelRatio.getFontScale() ajuda a depurar o layout em configurações de acessibilidade.numberOfLines está definido - principalmente no iOS.const typography = StyleSheet.create({ ... }) satisfies Record<string, TextStyle>;type Variant = keyof typeof typography.variant: Variant para autocompletar.Text aninhado herda fontSize, fontFamily, color e lineHeight do pai, a menos que substituído.fontFamily se o estilo do corpo pai já o definir.fontFamily para trechos monospaced).StyleSheet.create e composição de estilos de textouseFonts junto com Asset.loadAsyncTextVersões da Stack: Esta página foi escrita para React 19.2.3, React Native 0.86.0 e Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última atualização: 19 de jul. de 2026