Search code examples
cssreactjsfontsstyled-componentswebfonts

React load fonts dynamically from the backend


I want to be able to choose font I wish to download from backend via select and then use it in my project. User can change fonts and download new ones. I have problem that if font is fixed in my css like this:

export const MainContent = styled.div`
  @font-face {
        font-family: 'Lobster';
        src: local('Font Name'), local('FontName'),
        url ('http://localhost/font/lobster') format('woff');
       font-weight: bold;
    font-style: normal;
    font-display: swap;
    };
    font-family: 'Lobster';
`;

It is downloaded properly right after app starts and I can use it, however I don't want to have it fixed, tried few solutions so far like with WebFont:

import  WebFont  from 'webfontloader';

 
function App() {
enter code here
WebFont.load({
   custom: {
     families: ['Lobster'],
     urls: ['http://localhost/font/${fontname']  <= used fixed lobster in this case
   }
 });
...
}

But it throws error like = The resource from “http://localhost/font/lobster” was blocked due to MIME type (“font/ttf”) mismatch (X-Content-Type-Options: nosniff).

another idea was to send parameter which could replace for example lobster via props of styled component like

<MainContent fontName="lobsterTheSecond">
...
</MainContent>

However I don't really know how to pass props in @font-face as it keeps throwing errors.

Does anyone knows how can I add fonts dynamically from backend while app works? I'm out of ideas already


Solution

  • Not sure about WebFont but it can be done quite easy with styled components:

    First of all don't pass it to your 'MainContent' but rather pass props with new font to your globalStyles and then do something like that:

    const GlobalStyle = createGlobalStyle`
      body {
        @font-face {
            font-family: 'Lobster';
            src: `${props => 
            url ('http://localhost/font/${props.fontName}')` format('woff');
           font-weight: bold;
        font-style: normal;
        font-display: swap;
        };
      }
    `
    

    and pass it like:

       function App() {
        const [newFont, setNewFont] = useState('');
        
        return (
         <div>
          <GlobalStyle fontName{newFont} />
          <button onClick={() => setNewFont('myNewFont')>Click</button>
         </div>
        )
       }
    

    and then in your MainContent just use this font:

    const MainContent = styled.div`
      font-family: 'Lobster';
    `