diff --git a/docs/6.x/docs/guides/fonts.md b/docs/6.x/docs/guides/fonts.md
index 94a8eb40fe..cac73ee41e 100644
--- a/docs/6.x/docs/guides/fonts.md
+++ b/docs/6.x/docs/guides/fonts.md
@@ -67,6 +67,11 @@ Platform.select({
}),
```
+Material Design 3 splits the typescale across two font families: Brand (Display,
+Headline and Title Large) and Plain (Title Medium/Small, Label and Body). Both
+resolve to the same platform default above, so they are interchangeable until you
+override one of them.
+
:::
- #### Display
@@ -291,7 +296,7 @@ Platform.select({
"fontFamily": "Font",
"fontSize": 16,
"fontWeight": "400",
- "letterSpacing": 0.15,
+ "letterSpacing": 0.5,
"lineHeight": 24,
}
```
@@ -299,6 +304,23 @@ Platform.select({
+- #### Emphasized
+
+Each of the 15 variants above has an `Emphasized` counterpart — `displayLargeEmphasized`,
+`bodyMediumEmphasized`, and so on. They keep the size, line height and letter spacing of
+their baseline variant and only raise the weight: Display, Headline, Title Large and Body
+go to `"500"`, while Title Medium/Small and Label go to `"700"`.
+
+```json
+"bodyMediumEmphasized": {
+ "fontFamily": "Font",
+ "fontSize": 14,
+ "fontWeight": "500",
+ "letterSpacing": 0.25,
+ "lineHeight": 20,
+}
+```
+
:::info
If any component uses Paper's `Text` component, without specified variant, then `default` variant is applied:
diff --git a/src/components/Typography/Text.tsx b/src/components/Typography/Text.tsx
index 38a14fb423..5beeed1630 100644
--- a/src/components/Typography/Text.tsx
+++ b/src/components/Typography/Text.tsx
@@ -25,6 +25,9 @@ export type Props = React.ComponentProps & {
* Label: `labelLarge`, `labelMedium`, `labelSmall`
*
* Body: `bodyLarge`, `bodyMedium`, `bodySmall`
+ *
+ * Every variant also has an `Emphasized` counterpart, e.g. `displayLargeEmphasized`
+ * or `bodyMediumEmphasized`, which renders the same size at a heavier weight.
*/
variant?: VariantProp;
children: React.ReactNode;
diff --git a/src/theme/__tests__/fonts.test.js b/src/theme/__tests__/fonts.test.js
index 23e0f794ae..3c200412be 100644
--- a/src/theme/__tests__/fonts.test.js
+++ b/src/theme/__tests__/fonts.test.js
@@ -340,6 +340,40 @@ describe('configureFonts', () => {
});
});
+ it('resolves the Android font families per MD3 family assignment', () => {
+ mockPlatform('android');
+ const { typescale } = loadFonts();
+
+ for (const variant of ['bodyLarge', 'bodyMedium', 'bodySmall']) {
+ expect(typescale[variant]).toMatchObject({
+ fontFamily: 'sans-serif',
+ fontWeight: '400',
+ });
+ }
+
+ for (const variant of [
+ 'displayLargeEmphasized',
+ 'displayMediumEmphasized',
+ 'displaySmallEmphasized',
+ 'headlineLargeEmphasized',
+ 'headlineMediumEmphasized',
+ 'headlineSmallEmphasized',
+ 'titleLargeEmphasized',
+ ]) {
+ expect(typescale[variant]).toMatchObject({
+ fontFamily: 'sans-serif-medium',
+ fontWeight: '500',
+ });
+ }
+
+ for (const variant of ['displayLarge', 'headlineLarge', 'titleLarge']) {
+ expect(typescale[variant]).toMatchObject({
+ fontFamily: 'sans-serif',
+ fontWeight: '400',
+ });
+ }
+ });
+
it('should be deterministic', () => {
mockPlatform('ios');
const { configureFonts } = loadFonts();
diff --git a/src/theme/tokens/ref/typeface.ts b/src/theme/tokens/ref/typeface.ts
index fdf6993ae8..f62389b09b 100644
--- a/src/theme/tokens/ref/typeface.ts
+++ b/src/theme/tokens/ref/typeface.ts
@@ -9,8 +9,18 @@ export const typeface = {
ios: 'System',
default: 'sans-serif',
}),
+ brandMedium: Platform.select({
+ web: 'Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif',
+ ios: 'System',
+ default: 'sans-serif-medium',
+ }),
weightRegular: '400',
+ plainRegular: Platform.select({
+ web: 'Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif',
+ ios: 'System',
+ default: 'sans-serif',
+ }),
plainMedium: Platform.select({
web: 'Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif',
ios: 'System',
@@ -21,7 +31,9 @@ export const typeface = {
weightBold: '700',
} satisfies {
brandRegular?: string;
+ brandMedium?: string;
weightRegular: Font['fontWeight'];
+ plainRegular?: string;
plainMedium?: string;
weightMedium: Font['fontWeight'];
weightBold: Font['fontWeight'];
diff --git a/src/theme/tokens/sys/typography.ts b/src/theme/tokens/sys/typography.ts
index 289cbdedef..98177a5c8e 100644
--- a/src/theme/tokens/sys/typography.ts
+++ b/src/theme/tokens/sys/typography.ts
@@ -1,25 +1,37 @@
import type { Typescale } from '../../types';
import { typeface } from '../ref/typeface';
-const regularType = {
+const brandRegularType = {
fontFamily: typeface.brandRegular,
letterSpacing: 0,
fontWeight: typeface.weightRegular,
};
-const mediumType = {
+const brandMediumType = {
+ fontFamily: typeface.brandMedium,
+ letterSpacing: 0,
+ fontWeight: typeface.weightMedium,
+};
+
+const plainRegularType = {
+ fontFamily: typeface.plainRegular,
+ letterSpacing: 0,
+ fontWeight: typeface.weightRegular,
+};
+
+const plainMediumType = {
fontFamily: typeface.plainMedium,
letterSpacing: 0.15,
fontWeight: typeface.weightMedium,
};
-const emphasizedMediumType = {
+const plainMediumEmphasizedType = {
fontFamily: typeface.plainMedium,
letterSpacing: 0,
fontWeight: typeface.weightMedium,
};
-const emphasizedBoldType = {
+const plainBoldType = {
fontFamily: typeface.plainMedium,
letterSpacing: 0,
fontWeight: typeface.weightBold,
@@ -28,190 +40,184 @@ const emphasizedBoldType = {
/** md.sys.typescale.* */
export const typescale = {
displayLarge: {
- ...regularType,
+ ...brandRegularType,
letterSpacing: -0.25,
lineHeight: 64,
fontSize: 57,
},
displayMedium: {
- ...regularType,
+ ...brandRegularType,
lineHeight: 52,
fontSize: 45,
},
displaySmall: {
- ...regularType,
+ ...brandRegularType,
lineHeight: 44,
fontSize: 36,
},
headlineLarge: {
- ...regularType,
+ ...brandRegularType,
lineHeight: 40,
fontSize: 32,
},
headlineMedium: {
- ...regularType,
+ ...brandRegularType,
lineHeight: 36,
fontSize: 28,
},
headlineSmall: {
- ...regularType,
+ ...brandRegularType,
lineHeight: 32,
fontSize: 24,
},
titleLarge: {
- ...regularType,
+ ...brandRegularType,
lineHeight: 28,
fontSize: 22,
},
titleMedium: {
- ...mediumType,
+ ...plainMediumType,
lineHeight: 24,
fontSize: 16,
},
titleSmall: {
- ...mediumType,
+ ...plainMediumType,
letterSpacing: 0.1,
lineHeight: 20,
fontSize: 14,
},
labelLarge: {
- ...mediumType,
+ ...plainMediumType,
letterSpacing: 0.1,
lineHeight: 20,
fontSize: 14,
},
labelMedium: {
- ...mediumType,
+ ...plainMediumType,
letterSpacing: 0.5,
lineHeight: 16,
fontSize: 12,
},
labelSmall: {
- ...mediumType,
+ ...plainMediumType,
letterSpacing: 0.5,
lineHeight: 16,
fontSize: 11,
},
bodyLarge: {
- ...mediumType,
- fontWeight: typeface.weightRegular,
- fontFamily: typeface.brandRegular,
+ ...plainRegularType,
letterSpacing: 0.5,
lineHeight: 24,
fontSize: 16,
},
bodyMedium: {
- ...mediumType,
- fontWeight: typeface.weightRegular,
- fontFamily: typeface.brandRegular,
+ ...plainRegularType,
letterSpacing: 0.25,
lineHeight: 20,
fontSize: 14,
},
bodySmall: {
- ...mediumType,
- fontWeight: typeface.weightRegular,
- fontFamily: typeface.brandRegular,
+ ...plainRegularType,
letterSpacing: 0.4,
lineHeight: 16,
fontSize: 12,
},
displayLargeEmphasized: {
- ...emphasizedMediumType,
+ ...brandMediumType,
letterSpacing: -0.25,
lineHeight: 64,
fontSize: 57,
},
displayMediumEmphasized: {
- ...emphasizedMediumType,
+ ...brandMediumType,
lineHeight: 52,
fontSize: 45,
},
displaySmallEmphasized: {
- ...emphasizedMediumType,
+ ...brandMediumType,
lineHeight: 44,
fontSize: 36,
},
headlineLargeEmphasized: {
- ...emphasizedMediumType,
+ ...brandMediumType,
lineHeight: 40,
fontSize: 32,
},
headlineMediumEmphasized: {
- ...emphasizedMediumType,
+ ...brandMediumType,
lineHeight: 36,
fontSize: 28,
},
headlineSmallEmphasized: {
- ...emphasizedMediumType,
+ ...brandMediumType,
lineHeight: 32,
fontSize: 24,
},
titleLargeEmphasized: {
- ...emphasizedMediumType,
+ ...brandMediumType,
lineHeight: 28,
fontSize: 22,
},
titleMediumEmphasized: {
- ...emphasizedBoldType,
+ ...plainBoldType,
letterSpacing: 0.15,
lineHeight: 24,
fontSize: 16,
},
titleSmallEmphasized: {
- ...emphasizedBoldType,
+ ...plainBoldType,
letterSpacing: 0.1,
lineHeight: 20,
fontSize: 14,
},
labelLargeEmphasized: {
- ...emphasizedBoldType,
+ ...plainBoldType,
letterSpacing: 0.1,
lineHeight: 20,
fontSize: 14,
},
labelMediumEmphasized: {
- ...emphasizedBoldType,
+ ...plainBoldType,
letterSpacing: 0.5,
lineHeight: 16,
fontSize: 12,
},
labelSmallEmphasized: {
- ...emphasizedBoldType,
+ ...plainBoldType,
letterSpacing: 0.5,
lineHeight: 16,
fontSize: 11,
},
bodyLargeEmphasized: {
- ...emphasizedMediumType,
+ ...plainMediumEmphasizedType,
letterSpacing: 0.5,
lineHeight: 24,
fontSize: 16,
},
bodyMediumEmphasized: {
- ...emphasizedMediumType,
+ ...plainMediumEmphasizedType,
letterSpacing: 0.25,
lineHeight: 20,
fontSize: 14,
},
bodySmallEmphasized: {
- ...emphasizedMediumType,
+ ...plainMediumEmphasizedType,
letterSpacing: 0.4,
lineHeight: 16,
fontSize: 12,
},
default: {
- ...regularType,
+ ...brandRegularType,
},
};
diff --git a/src/theme/types/typography.ts b/src/theme/types/typography.ts
index 57fcf3f67e..f7ad73b80f 100644
--- a/src/theme/types/typography.ts
+++ b/src/theme/types/typography.ts
@@ -37,7 +37,22 @@ export type TypescaleKey =
| 'labelSmall'
| 'bodyLarge'
| 'bodyMedium'
- | 'bodySmall';
+ | 'bodySmall'
+ | 'displayLargeEmphasized'
+ | 'displayMediumEmphasized'
+ | 'displaySmallEmphasized'
+ | 'headlineLargeEmphasized'
+ | 'headlineMediumEmphasized'
+ | 'headlineSmallEmphasized'
+ | 'titleLargeEmphasized'
+ | 'titleMediumEmphasized'
+ | 'titleSmallEmphasized'
+ | 'labelLargeEmphasized'
+ | 'labelMediumEmphasized'
+ | 'labelSmallEmphasized'
+ | 'bodyLargeEmphasized'
+ | 'bodyMediumEmphasized'
+ | 'bodySmallEmphasized';
export type TypescaleStyle = {
fontFamily: string;