Guides
Custom Font
Adding custom fonts to your application or website is a typical requirement for projects. Panda recommends using custom fonts through CSS variables for consistency.
Setup
Next.js
Next.js provides a built-in automatic self-hosting for any font file by using the next/font
module. It allows you to conveniently use all Google Fonts and any local font with performance and privacy in mind.
Here's an example of how to load a local "Mona Sans" font and a Google Font "Fira Code" in your Next.js project.
import { Fira_Code } from 'next/font/google'
import localFont from 'next/font/local'
export const MonaSans = localFont({
src: '../fonts/Mona-Sans.woff2',
display: 'swap',
variable: '--font-mona-sans'
})
export const FiraCode = Fira_Code({
weight: ['400', '500', '700'],
display: 'swap',
subsets: ['latin'],
variable: '--font-fira-code'
})
Ideally, you should load the font in the layout file.
Next, you need to add the font variables to your HTML document. You can do this using either the App Router or the Pages Router.
App Router
import { FiraCode, MonaSans } from '../styles/font'
export default function Layout(props) {
const { children } = props
return (
<html className={`${MonaSans.variable} ${FiraCode.variable}`}>
<body>{children}</body>
</html>
)
}
Note 🚨: By default, Next.js attaches the className for the fonts to the <body>
element, for panda to appropriately load fonts, update the code to attach the className
to the <html>
element.
Pages Router
import { FiraCode, MonaSans } from '../styles/font'
export default function App({ Component, pageProps }) {
return (
<>
<style jsx global>
{`
:root {
--font-mona-sans: ${MonaSans.style.fontFamily};
--font-fira-code: ${FiraCode.style.fontFamily};
}
`}
</style>
<Component {...pageProps} />
</>
)
}
Fontsource
Fontsource (opens in a new tab) streamlines the process of integrating fonts into your web application.
To begin, install your desired font package:
pnpm add @fontsource-variable/fira-code
Next, import the font into your project:
import '@fontsource-variable/fira-code'
Lastly, create a variable to use it as a token in the panda config
:root {
--font-fira-code: 'Fira Code Variable', monospace;
}
Vanilla CSS
You can leverage the native font-face CSS property to load custom fonts in your project.
@font-face {
font-family: 'Mona Sans';
src: url('../fonts/Mona-Sans.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}
Then alias the font names to css variables.
:root {
--font-mona-sans: 'Mona Sans', sans-serif;
}
Global Font Face
You can also define global font face in your panda config.
export default defineConfig({
globalFontface: {
Fira: {
src: 'url(/fonts/fira.woff2) format("woff2")',
fontWeight: 400,
fontStyle: 'normal',
fontDisplay: 'swap'
}
}
})
You can also define multiple font sources for the same weight.
export default defineConfig({
globalFontface: {
Fira: {
src: [
'url(/fonts/fira.woff2) format("woff2")',
'url(/fonts/fira.woff) format("woff")'
],
fontWeight: 400,
fontStyle: 'normal',
fontDisplay: 'swap'
}
}
})
You can also define multiple font weights.
export default defineConfig({
globalFontface: {
Fira: [
{
src: 'url(/fonts/fira.woff2) format("woff2")',
fontWeight: 400,
fontStyle: 'normal',
fontDisplay: 'swap'
},
{
src: 'url(/fonts/fira-bold.woff2) format("woff2")',
fontWeight: 700,
fontStyle: 'normal',
fontDisplay: 'swap'
}
]
}
})
Then expose the font names to css variables.
:root {
--font-fira-code: 'Fira Code Variable', monospace;
}
You can also use globalVars in your panda config to define the variables.
export default defineConfig({
globalVars: {
'--font-fira-code': 'Fira Code Variable, monospace'
}
})
Update Panda Config
export default defineConfig({
theme: {
extend: {
tokens: {
fonts: {
fira: { value: 'var(--font-fira-code), Menlo, monospace' },
mona: { value: 'var(--font-mona-sans), sans-serif' }
}
}
}
}
})
Use the custom fonts
import { css } from '../styled-system/css'
function Page() {
return (
<div>
<h1 className={css({ fontFamily: 'mona' })}>Mona Sans</h1>
<code className={css({ fontFamily: 'fira' })}>Fira Code</code>
</div>
)
}