Modern typography for SaaS, fintech, and developer tools. Features Satoshi, Geist, Inter, and DM Sans with complete React Native implementation.
Clean, modern typography used by Linear, Vercel, Notion, Stripe, and Figma.
| Font | Style | Best For | License |
|---|---|---|---|
| Satoshi | Geometric, clean | Fintech, AI tools | Free (Fontshare) |
| Geist | Sharp, technical | Dev tools, dashboards | Free (Vercel) |
| Inter | Versatile, readable | SaaS, web apps | Free (Google) |
| DM Sans | Friendly geometric | Data platforms | Free (Google) |
| Font | Style | Best For |
|---|---|---|
| Plus Jakarta Sans | Rounded geometric | Friendly SaaS |
| General Sans | Neutral, modern | Enterprise tools |
| Space Grotesk | Technical, unique | Crypto, Web3 |
| Outfit | Variable, clean | Modern dashboards |
Heading: Satoshi Bold (700)
Body: Satoshi Regular (400)
Mono: JetBrains Mono
Heading: Geist Bold (700)
Body: Geist Regular (400)
Mono: Geist Mono
Heading: Inter Display Semi-Bold (600)
Body: Inter Regular (400)
Mono: SF Mono / JetBrains Mono
Heading: DM Sans Bold (700)
Body: DM Sans Regular (400)
Mono: IBM Plex Mono
npx expo install expo-font @expo-google-fonts/inter @expo-google-fonts/dm-sans
// apps/mobile/app/_layout.tsx
import { useFonts } from 'expo-font';
import {
Inter_400Regular,
Inter_500Medium,
Inter_600SemiBold,
Inter_700Bold,
} from '@expo-google-fonts/inter';
import {
DMSans_400Regular,
DMSans_500Medium,
DMSans_700Bold,
} from '@expo-google-fonts/dm-sans';
import * as SplashScreen from 'expo-splash-screen';
SplashScreen.preventAutoHideAsync();
export default function RootLayout() {
const [fontsLoaded] = useFonts({
'Inter-Regular': Inter_400Regular,
'Inter-Medium': Inter_500Medium,
'Inter-SemiBold': Inter_600SemiBold,
'Inter-Bold': Inter_700Bold,
'DMSans-Regular': DMSans_400Regular,
'DMSans-Medium': DMSans_500Medium,
'DMSans-Bold': DMSans_700Bold,
});
useEffect(() => {
if (fontsLoaded) {
SplashScreen.hideAsync();
}
}, [fontsLoaded]);
if (!fontsLoaded) return null;
return <Stack />;
}
For fonts not on Google Fonts, download and add to assets/fonts/:
// apps/mobile/app/_layout.tsx
const [fontsLoaded] = useFonts({
'Satoshi-Regular': require('../assets/fonts/Satoshi-Regular.otf'),
'Satoshi-Medium': require('../assets/fonts/Satoshi-Medium.otf'),
'Satoshi-Bold': require('../assets/fonts/Satoshi-Bold.otf'),
'Geist-Regular': require('../assets/fonts/Geist-Regular.otf'),
'Geist-Medium': require('../assets/fonts/Geist-Medium.otf'),
'Geist-Bold': require('../assets/fonts/Geist-Bold.otf'),
'GeistMono-Regular': require('../assets/fonts/GeistMono-Regular.otf'),
});
// packages/ui/src/tokens/typography.ts
export const techStartupTypography = {
fonts: {
heading: 'Satoshi-Bold',
headingMedium: 'Satoshi-Medium',
body: 'Satoshi-Regular',
bodyMedium: 'Satoshi-Medium',
mono: 'GeistMono-Regular',
},
sizes: {
// Display
display1: { fontSize: 56, lineHeight: 64, letterSpacing: -1.5 },
display2: { fontSize: 48, lineHeight: 56, letterSpacing: -1.0 },
// Headings
h1: { fontSize: 36, lineHeight: 44, letterSpacing: -0.5 },
h2: { fontSize: 28, lineHeight: 36, letterSpacing: -0.3 },
h3: { fontSize: 22, lineHeight: 28, letterSpacing: 0 },
h4: { fontSize: 18, lineHeight: 24, letterSpacing: 0 },
// Body
bodyLarge: { fontSize: 18, lineHeight: 28, letterSpacing: 0 },
body: { fontSize: 16, lineHeight: 24, letterSpacing: 0 },
bodySmall: { fontSize: 14, lineHeight: 20, letterSpacing: 0 },
// Caption/Label
caption: { fontSize: 12, lineHeight: 16, letterSpacing: 0.2 },
label: { fontSize: 11, lineHeight: 14, letterSpacing: 0.5, textTransform: 'uppercase' },
},
weights: {
regular: '400',
medium: '500',
semibold: '600',
bold: '700',
},
};
// packages/ui/src/components/Text.tsx
import { Text as RNText, TextStyle, StyleSheet } from 'react-native';
import { techStartupTypography as t } from '../tokens/typography';
type TextVariant = 'display1' | 'display2' | 'h1' | 'h2' | 'h3' | 'h4' |
'bodyLarge' | 'body' | 'bodySmall' | 'caption' | 'label';
interface TextProps {
variant?: TextVariant;
weight?: 'regular' | 'medium' | 'semibold' | 'bold';
mono?: boolean;
children: React.ReactNode;
style?: TextStyle;
}
export function Text({
variant = 'body',
weight = 'regular',
mono = false,
children,
style
}: TextProps) {
const fontFamily = mono
? t.fonts.mono
: weight === 'bold'
? t.fonts.heading
: weight === 'medium'
? t.fonts.bodyMedium
: t.fonts.body;
return (
<RNText style={[t.sizes[variant], { fontFamily }, style]}>
{children}
</RNText>
);
}
// Usage
<Text variant="h1">Dashboard</Text>
<Text variant="body" weight="medium">Welcome back</Text>
<Text variant="caption" mono>v1.0.0</Text>
| Brand | Primary Font | Secondary |
|---|---|---|
| Linear | Inter | SF Mono |
| Vercel | Geist | Geist Mono |
| Stripe | Inter + custom | - |
| Notion | Inter | Roboto Mono |
| Figma | Inter | - |