Experimental fonts API
Added in:
astro@5.7.0
Beta
This experimental feature allows you to use fonts from your filesystem and various providers through a unified API:
import { defineConfig } from 'astro/config'
export default defineConfig({ experimental: { fonts: { families: ['Roboto'] } }})
---import { Font } from 'astro:assets'---
<Font family='Roboto' preload />
<style>body { font-family: var(--astro-font-roboto);}</style>
Configuring experimental fonts
Section titled Configuring experimental fontsTo start using fonts, register a font family in experimental.fonts.families
:
import { defineConfig } from 'astro/config'
export default defineConfig({ experimental: { fonts: { families: ['Roboto'] } }})
Configuring a remote font family
Section titled Configuring a remote font familyA font family can be registered as a string or an object:
import { defineConfig } from 'astro/config'
export default defineConfig({ experimental: { fonts: { families: [ 'Roboto', // Shortand for { name: 'Roboto' } { name: 'Lato' } ] } }})
It accepts various options:
The required font family name:
{ name: 'Roboto'}
An optional alias name. This is useful to avoid conflicts, especially as an integration:
{ name: 'Roboto', as: 'Custom'}
provider
Section titled providerAn optional provider name. Defaults to google
and accepts one of these values: google
, local
or any name from other registered providers:
{ providers: [custom()], families: [ { name: 'Roboto', provider: 'custom' } ]}
weights
Section titled weightsAn optional array of font weights (strings and numbers are allowed). Defaults to ['400']
:
{ name: 'Roboto', weights: [200, '300', 'bold']}
styles
Section titled stylesAn optional array of font styles. Defaults to ['normal', 'italic']
:
{ name: 'Roboto', styles: ['oblique']}
subsets
Section titled subsetsAn optional array of font subsets. Defaults to ['cyrillic-ext', 'cyrillic', 'greek-ext', 'greek', 'vietnamese', 'latin-ext', 'latin']
:
{ name: 'Roboto', subsets: ['latin']}
fallbacks
Section titled fallbacksAn optional array of font fallbacks:
{ name: 'Roboto', fallbacks: ['Custom', 'sans-serif']}
If the latest fallback if a generic family name, Astro will try to generate an optimized fallback using font metrics.
automaticFallback
Section titled automaticFallbackAn optional boolean flag to enable/disable the automatic fallback generation described above. Defaults to false
:
{ name: 'Roboto', fallbacks: ['Arial', 'sans-serif'], automaticFallback: false}
display
Section titled displayAn optional font display:
{ name: 'Roboto', display: 'swap'}
unicodeRange
Section titled unicodeRangeAn optional unicode range:
{ name: 'Roboto', unicodeRange: 'U+26'}
stretch
Section titled stretchAn optional font stretch:
{ name: 'Roboto', stretch: 'condensed'}
featureSettings
Section titled featureSettingsOptional font feature settings:
{ name: 'Roboto', featureSettings: '"smcp" 2'}
variationSettings
Section titled variationSettingsOptional font variation settings:
{ name: 'Roboto', variationSettings: '"xhgt" 0.7'}
Using other providers
Section titled Using other providersMore providers can be used by registering them in fonts.providers
:
import { defineConfig, fontProviders } from 'astro/config'
export default defineConfig({ experimental: { fonts: { providers: [fontProviders.fontsource()], families: [{ name: 'Roboto', provider: 'fontsource' }] } }})
fontProviders
supports most unifont providers (except google
since it’s built-in):
adobe
bunny
fontshare
fontsource
Configuring a local font
Section titled Configuring a local fontTo use local fonts, set provider: 'local'
and specify some sources:
import { defineConfig } from 'astro/config'
export default defineConfig({ experimental: { fonts: { families: [{ name: 'Roboto', provider: 'local', src: [{ paths: ['./src/assets/fonts/roboto.woff2'] }] }] } }})
Here are the configuration differences with a remote font family:
- All options from remote font families except
weights
,styles
andsubsets
- There’s a required
src
option
A required option of sources for your font. It’s an array of objects with the following properties:
- All options from remote font families except
fallbacks
,automaticFallback
andsubsets
paths
: An array of paths relative to project root
Using fonts
Section titled Using fontsOnce you’ve configured the fonts in your config, you can start using them by calling the <Font />
component and consuming the CSS variable.
Font component
Section titled Font componentastro:assets
exports a <Font />
component:
---import { Font } from 'astro:assets'---
<Font family='Roboto' />
It accepts various options:
family
Section titled familyA required font family name.
If you specified as
for a given font family, it must be used instead of name
.
preload
Section titled preloadAn optional boolean to generate preload links. Defaults to false
:
---import { Font } from 'astro:assets'---
<Font family='Roboto' preload />
CSS variable
Section titled CSS variableThe <Font />
component registers some styles, including CSS variables:
<style>body { font-family: var(--astro-font-roboto);}</style>
Generated CSS variables follow the --astro-font-name
pattern, where name
is converted to kebab case.
If you specified as
for a given font family, it is used instead of name
to generate the CSS variable identifier.
Advanced
Section titled AdvancedCreating a custom font provider
Section titled Creating a custom font providerAn Astro font provider is made of 2 parts: the config object and the actual implementation.
Config object
Section titled Config objectYou can use the defineFontProvider()
type helper:
import { defineFontProvider } from 'astro/config'
interface Config { // ...}
export function myProvider(config: Config) { return defineFontProvider({ name: 'my-provider', entrypoint: new URL('./implementation.js', import.meta.url), config })}
- The
entrypoint
can be a URL, a path relative to the root or a package import - The
config
is optional and must be serializable
Implementation
Section titled ImplementationThe file linked by the the entrypoint
must contain a named provider
export, which is a unifont provider:
import { defineFontProvider } from "unifont"
export const provider = defineFontProvider("my-provider", async (options, ctx) => { // ...})
We recommend you look at unifont providers’ source to learn more about how to create a unifont provider.
Registering fonts as an integration
Section titled Registering fonts as an integrationAs an integration, you may want to use fonts but you want to avoid conflicts with the user. Eg. both the user and your integration use Roboto but with different settings.
To make sure there’s no conflict, use the as
prop and make sure to make it specific enough:
updateConfig({ experimental: { fonts: { families: [ { name: 'Roboto', as: 'CustomIntegration: Roboto', // ... } ] } }})
To get proper autocompletion when using the <Font />
component, you’ll need to use module augmentation:
declare module 'astro:assets' { export type FontFamily = 'CustomIntegration: Roboto'}
Caching
Section titled CachingIn order to avoid downloading files if not needed, caching has been implemented.
Development
Section titled Development- If a font file is requested, it will first check if it has been downloaded locally and load it. Otherwise it will make a network request
- Font files are downloaded on demand. We only download them if they’re requested by the browser
- They are not cached in the browser however, to avoid getting stale assets
- To clear the cache, remove the
.astro/fonts
directory
Build
Section titled Build- All font files are requested. For each file, it will first check if it has been downloaded locally and load it. Otherwise it will make a network request
- Font files are copied to the
_astro/fonts
output directory, so they can benefit from HTTP caching of static assets - To clear the cache, remove the
node_modules/.astro/font
directory
Further reading
Section titled Further readingFor full details and to give feedback on this experimental API, see the Fonts RFC.
Reference