Search code examples
componentschakra-uifont-familyheading

Why are custom fonts set in theme not rendering in the Heading component?


Reading and learning Chakra UI and trying to set a default fontFamily for the Heading component I've tried to implement the font I've set in heading:

import { extendTheme } from '@chakra-ui/react'

const theme = extendTheme({
  fonts: {
    heading: `'Custom Font', sans-serif`,
  },
  styles: {
    global: {
      h1: {
        fontFamily: 'heading',
        color: 'blue',
      },
    },
  },
})

export default theme

color changes but the font will not.


Edit after answer and further research. This seems to be an active issue unless my approach is incorrect so I will outline everything I've done:

src/theme/index.js:

import { extendTheme, theme as defaultTheme } from '@chakra-ui/react'

const theme = extendTheme(
  {
    ...defaultTheme, // Dont think this is needed but was in an answer
    fonts: {
      heading: `'Foo Bar', sans-serif`,
    },
    
  },
)

export default theme

Font isn't on Fontsource so tried the @font-face approach:

src/theme/Fonts.js:

import React from 'react'
import { Global } from '@emotion/react'

const Fonts = () => (
  <Global
    styles={`
    @font-face {
      font-family: 'Foo Bar';
      font-style: normal;
      font-weight: normal;
      font-display: swap;
      src: local('Foo Bar'), url('./fonts/Foo-Bar.woff2') format('woff2');
    }
    `}
  />
)

export default Fonts

font is stored in the directory structure:

src/theme/fonts/Foo-Bar.woff2

Gatsby Wrapper:

import React from 'react'
import PropTypes from 'prop-types'
import { ChakraProvider } from '@chakra-ui/react'

// Theme
import theme from './src/theme'
import Fonts from './src/theme/Fonts'

function RootWrapper({ element }) {
  return (
    <ChakraProvider theme={theme}>
      <Fonts /> // <!--- FONTS HERE
      {element}
    </ChakraProvider>
  )
}

RootWrapper.propTypes = {
  element: PropTypes.node.isRequired,
}

export default RootWrapper

When I log the theme I can see:

fonts: {
  heading: Foo Bar
}

Per the answer below when I check var(--chakra-fonts-heading); it still shows:

--chakra-fonts-heading: -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";

The only way I can get custom fonts to work is to use Text and bring in a textStyle:

<Text as="h1" textStyle="h1">test</Text>

I think this approach dismisses what Heading is supposed to be for.

Research:

dependencies:

"@chakra-ui/gatsby-plugin": "^3.1.3",
"@chakra-ui/icons": "^2.1.0",
"@chakra-ui/react": "^2.8.0",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",

why will a custom fonts not render by default but only when passed as a textStyle? How can I, by theme default use a heading font for all headers?


Solution

  • Tested with @chakra-ui/react v2.8.0

    Edit for additional information provided

    I'm suspicious that it could be a cache issue based on previous issues I've seen with Gatsby and running a gatsby clean resolving them. I haven't been able to recreate the issue based on what you've provided - the heading font displays for me in multiple configurations with two different fonts, which is why I'm wondering if it's a dev environment anomaly.

    I can't pinpoint why specifically it's not working, but I'll share a solution that works for me.

    With Gatsby, @chakra-ui/react, and @chakra-ui/gatsby-plugin:

    1. Import local fonts

    Gatsby Using Local Fonts Reference

    1. Upload your fonts. I uploaded mine to src/fonts in this example. Alternatively to the static folder depending on use case.
    2. Create a CSS file with @font-face. I created the example in src/fonts.css.
    @font-face {
        font-family: "Open Sans";
        font-style: normal;
        font-weight: 400;
        font-display: swap;
        src: url("./fonts/OpenSans-Regular.ttf") format("truetype");
    }
    
    1. Create/edit gatsby-browser.js in the root folder and add this to load the fonts globally. Gatsby Global Styles
    import "./src/fonts.css"
    
    1. Create/edit gatsby-ssr.js in root folder to preload your font files. gatsby-ssr
    import * as React from "react"
    
    export const onRenderBody = ({ setHeadComponents }) => {
        setHeadComponents([
            <link
                rel="preload"
                href="./src/fonts/OpenSans-Regular.ttf"
                as="font"
                type="font/ttf"
                crossOrigin="anonymous"
                key="yourFontKey"
            />,
        ])
    }
    

    2. Create a shadow of the Chakra theme file for customizations

    Chakra Gatsby Plugin Reference

    1. Create src/@chakra-ui/gatsby-plugin/theme.js. The Chakra gatsby-plugin automatically adds the ChakraProvider wrapper, so there's no need to add it separately unless you're doing something custom.
    2. Add your customizations. Heading example below:
    import { extendTheme } from '@chakra-ui/react'
    
    const theme = {
       fonts: {
           heading: `'Open Sans', sans-serif`
       }
    }
    
    export default extendTheme(theme);
    

    3. Restart Gatsby server

    1. (Optional) gatsby clean to clear the cache - this sometimes resolves new/changed font and other display issues.
    2. Restart the Gatsby server.

    Working sandbox example


    Original answer to: Chakra UI theming how to set default fontFamily for Heading component?

    I tried your first code snippet with a custom font and it's working successfully for me.

    This is what works for me to import and set font families for the Heading component (and any other components that by default use the Chakra 'heading' font):

    import {extendTheme} from "@chakra-ui/react";
    import '@fontsource-variable/yourFont';
    
    const myTheme = extendTheme({
        fonts: {
            heading: `'yourFont Variable', sans-serif`
        }
    })
    
    export default myTheme;
    
    

    The Heading component already has the Chakra heading font family applied in their default theme styles (see Heading link above for source code, line 4).

    To check if the font is attempting to apply in the browser, select your heading component in dev tools and check if the CSS has font-family: var(--chakra-fonts-heading);, which means it's getting the Chakra 'heading' style applied. If that's set and the theme --chakra-fonts-heading CSS shows the correct fonts, yet the font is not displaying in the browser, there might be an issue with the font import/render. I've noticed sometimes after I install new fonts I have to stop/start the server for them to pick up.

    Hope this helps!