Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implement self hosted font in Material-UI custom theme (ReactJS)?

At the moment I'm setting up my first project using Material-UI for ReactJS. As I want to customise the default theme with, for example, a custom font (hosted on the server, not Google Fonts or something similar) I started working on this.

However, while not getting any errors during build or in the browser console, it just does not load. I've already tried multiple proposed solutions from StackOverflow and the Material-UI repo but I cannot get it to work and as such I'm at a loss what to do next.

I've already tried several approaches that are suggested in other threads on StackOverflow, in the official Material-UI docs and in the issues on the Material-UI GitHub repository, but to no avail. I'm probably overlooking something obvious, or scrambling different concepts so any help would be much appreciated :)

Theme definition:

import {createMuiTheme} from "@material-ui/core";

import Penna from "./../../assets/fonts/penna.otf";

const pennaFont = {
    fontFamily: 'Penna',
    fontStyle: 'normal',
    fontDisplay: 'swap',
    fontWeight: 400,
    src: `
    local('Penna'),
    url(${Penna})
  `,
}

const MUI_THEME = createMuiTheme({
    typegraphy: {
        fontFamily: ['Penna', "'Helvetica Neue'", 'Helvetica', 'Arial', 'sans-serif'].join(","),
        fontSize: "16px",
        fontWeightLight: "300",
        fontWeightRegular: "400",
        fontWeightMedium: "700",
    },
    overrides: {
        MuiCssBaseline: {
            '@global': {
                '@font-family': [pennaFont],
            },
        },
    },
});

export default MUI_THEME;

Top-level entry point:


// ReactJS related
import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter} from 'react-router-dom';

// Material-UI
import {ThemeProvider} from "@material-ui/styles";
import CssBaseline from '@material-ui/core/CssBaseline';

// Custom
import MuiTheme from "./base/MuiTheme";
import Main from "./Main";

ReactDOM.render(
    <ThemeProvider theme={MuiTheme}>
        <CssBaseline/>
        <BrowserRouter>
            <Main/>
        </BrowserRouter>
    </ThemeProvider>,
    document.getElementById("root"));

Webpack config:

const path = require("path");

module.exports = {
    mode: "development",
    entry: path.join(__dirname, "../..", "src", "client", "js", "index.js"),
    output: {
        path: path.join(__dirname, "../..", "dist", "js"),
        filename: "index.js"
    },
    module: {
        rules: [
            {
                exclude: path.join(__dirname, "node_modules"),
                test: /\.jsx?$/,
                use: {
                    loader: "babel-loader",
                },
            },
            {
                test: /\.scss$/,
                use: [{
                    loader: "style-loader"
                }, {
                    loader: "css-loader"
                }, {
                    loader: "sass-loader",
                    options: {}
                }]
            },
            {
                test: /\.(woff(2)?|eot|ttf|otf)$/,
                use: [{
                    loader: 'file-loader',
                    options: {
                        name: '[name].[ext]',
                        outputPath: 'assets/fonts'
                    }
                }]
            }
        ],
    },
    resolve: {
        extensions: [".css", ".scss", ".js", ".jsx", ".json", ".otf"],
    },
    target: "web",
    context: __dirname,
    stats: {
        colors: true,
        reasons: true,
        chunks: true,
    },
};

package.json:

{
  "name": "romys-hairstyling",
  "version": "0.0.1",
  "description": "Official page for Romy's Hairstyling.",
  "main": "index.js",
  "scripts": {
    "build:react": "webpack --config ./config/webpack/webpack.config.js",
    "build:scss:base": "sass src/client/scss/base/_index.scss dist/css/base.css",
    "copy:html": "node ./scripts/copy.js ./src/client/index.html ./dist/index.html -f",
    "copy:images": "node ./scripts/copy.js ./src/client/assets/images ./dist/images -Rf",
    "watch": "npm-run-all -p watch:react watch:scss:base watch:html watch:images -l",
    "watch:react": "webpack --config ./config/webpack/webpack.config.js --watch --watch-aggregate-timeout 500 --watch-poll 1000 --info-verbosity verbose",
    "watch:scss:base": "chokidar \"./src/client/scss/base\" -c \"npm run build:scss:base\" --verbose --initial",
    "watch:html": "chokidar \"./src/client/index.html\" -c \"npm run copy:html\" --verbose --initial",
    "watch:images": "chokidar \"./src/client/assets/images\" -c \"npm run copy:images\" --verbose --initial",
    "start:server": "nodemon ./src/server/server.js",
    "test:eslint:summary": "eslint -c ./.eslintrc ./src/client/js/index.js",
    "test:eslint:fix": "eslint --fix -c ./.eslintrc ./src/client/js/index.js"
  },
  "keywords": [
    "Romy",
    "Hairstyling"
  ],
  "author": "Tomas Schlepers",
  "license": "ISC",
  "dependencies": {
    "@material-ui/core": "^3.9.3",
    "@material-ui/icons": "^3.0.2",
    "express": "^4.16.4",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-router-dom": "^4.3.1"
  },
  "devDependencies": {
    "@babel/core": "^7.4.3",
    "@babel/preset-env": "^7.4.3",
    "@babel/preset-react": "^7.0.0",
    "@material-ui/styles": "^4.0.0",
    "babel-loader": "^8.0.5",
    "chokidar-cli": "^1.2.2",
    "css-loader": "^2.1.1",
    "eslint": "^5.16.0",
    "eslint-plugin-react": "^7.12.4",
    "file-loader": "^3.0.1",
    "node-sass": "^4.12.0",
    "nodemon": "^1.18.11",
    "normalize.css": "^8.0.1",
    "npm-run-all": "^4.1.5",
    "sass": "^1.20.1",
    "sass-loader": "^7.1.0",
    "shelljs": "^0.8.3",
    "style-loader": "^0.23.1",
    "webpack": "^4.30.0",
    "webpack-cli": "^3.3.1"
  }
}

As said I do not get any error messages whatsoever. I can also see in the compiled JS code that there are references to the Penna font, but when looking in the rendered DOM tree I nowhere see the defined custom theme.

like image 577
Togren Avatar asked May 24 '19 05:05

Togren


People also ask

How do I add a font to material UI theme?

To self-host fonts, download the font files in ttf , woff , and/or woff2 formats and import them into your code. ⚠️ This requires that you have a plugin or loader in your build process that can handle loading ttf , woff , and woff2 files. Fonts will not be embedded within your bundle.

How do I use Google fonts in material UI theme?

Method 1: Use Google Fonts CDN To be able to use the fonts, you'll have to initialize it using the CreateMuiTheme which is an API provided by Material UI that generates a custom theme based on the options received and ThemeProvider which is a component used to inject custom themes into your application.


2 Answers

Step 1

add your font files to the fonts directory (./fonts/Raleway-Regular.woff2)


Step 2

Import fonts into the code in woff/woff2 formats. Documentation stated ttf/woff/woff2 supports, but ttf have not worked for me.

https://material-ui.com/customization/typography/

import RalewayWoff2 from './fonts/Raleway-Regular.woff2';
import RalewayBoldWoff2 from './fonts/Raleway-Bold.woff2';

const raleway = {
  fontFamily: 'Raleway',
  fontStyle: 'normal',
  fontDisplay: 'swap',
  fontWeight: 400,
  src: `
    local('Raleway'),
    local('Raleway-Regular'),
    url(${RalewayWoff2}) format('woff2')
  `,
};

const ralewayBold = {
  fontFamily: 'Raleway',
  fontStyle: 'normal',
  fontDisplay: 'swap',
  fontWeight: 700,
  src: `
    local('Raleway'),
    local('Raleway-Bold'),
    url(${RalewayBoldWoff2}) format('woff2')
  `,
};
Step 3

Run this in the terminal to use loader in your build process that can handle loading files

npm install --save-dev file-loader

refer https://jimthedev.com/2016/07/28/using-google-fonts-in-webpack-and-react/


Step 4

Then define the font in the theme

const theme = createMuiTheme({
  typography: {
    fontFamily: [
      'Raleway',
      '-apple-system',
      'BlinkMacSystemFont',
      '"Segoe UI"',
      'Roboto',
      '"Helvetica Neue"',
      'Arial',
      'sans-serif',
      '"Apple Color Emoji"',
      '"Segoe UI Emoji"',
      '"Segoe UI Symbol"',
    ].join(','),
  },
  overrides: {
    MuiCssBaseline: {
      '@global': {
        '@font-face': [raleway,ralewayBold],
      },
    },
  },
});

You can use the bold font that imported like this.

font-weight: 700;

like image 148
Janith Malshan Avatar answered Oct 26 '22 13:10

Janith Malshan


Just to add to the comment above. ttf works but you have to specify the format as truetype. So it will look like this instead.

import Raleway from './fonts/Raleway-Regular.tff';

const raleway = {
  fontFamily: 'Raleway',
  fontStyle: 'normal',
  fontDisplay: 'swap',
  fontWeight: 400,
  src: `
    url(${Raleway}) format('truetype')
  `,
};
like image 24
msrc Avatar answered Oct 26 '22 12:10

msrc