Setting up Semantic UI React and Next.js with a custom theme

A simple starter project for using Semantic UI React with a custom theme built on the Next.js framework.


tl;dr:
You can view the finished project here https://github.com/danownsthisspace/next-js-react-semantic-ui-custom-theme

Recently I setup a project which used Next.js as the framework and I wanted to incorporate Semantic UI React in it with a custom theme.
There were a couple of gotchas during the process so I decided to put the starter project on GitHub.

package.json

  
{
	"name": "next-js-react-semantic-ui-custom-theme",
	"version": "0.1.0",
	"private": true,
	"scripts": {
		"build-semantic": "cd ./semantic && gulp build-css build-assets",
		"watch-semantic": "cd ./semantic && yarn run build-semantic && gulp watch",
		"dev": "next dev",
		"build": "next build",
		"start": "next start"
	},
	"dependencies": {
		"fomantic-ui": "^2.7.8",
		"next": "9.0.5",
		"react": "16.9.0",
		"react-dom": "16.9.0",
		"semantic-ui-react": "^0.88.0"
	},
	"devDependencies": {
		"@zeit/next-css": "^1.0.1",
		"file-loader": "^3.0.1",
		"url-loader": "^1.1.2"
	}
}
  

Instead of using the original Semantic UI library, I went with Fomantic UI which is a community fork of the Semantic UI Library because it is still maintained and it works with the latest version of Gulp. The reason you need gulp is to package Fomantic to use your custom theme.

next.config.js

  
    const withCSS = require('@zeit/next-css')

    module.exports = withCSS({
      target: 'serverless',
      webpack(config) {
        // Fixes npm packages that depend on `fs` module
        config.node = {
          fs: 'empty'
        }
        config.module.rules.push({
          test: /\.(png|svg|eot|otf|ttf|woff|woff2)$/,
          use: {
            loader: 'url-loader',
            options: {
              limit: 8192,
              publicPath: '/_next/static/',
              outputPath: 'static/',
              name: '[name].[ext]'
            }
          }
        })
        return config
      }
    })
  

I included the withCSS module for next.config so that I could include the Fomantic UI library via an es6 import instead of using a link tag in the Head section:

pages/_app.js

  
  import '../semantic/dist/semantic.min.css'

  import React from 'react'
  import App from 'next/app'

  class MyApp extends App {
    render() {
      const { Component, pageProps } = this.props
      return <Component {...pageProps} />
    }
  }

  export default MyApp
  

pages/_document.js

  
    import React from "react";
    import Document, { Head, Main, NextScript } from "next/document";

    export default class extends Document {

      static async getInitialProps(ctx) {
        const initialProps = await Document.getInitialProps(ctx)
        return { ...initialProps }
      }

      render() {
        return (
          <html lang="en">
            <Head>
              <meta charSet="UTF-8" />
              <meta
                name="viewport"
                content="width=device-width, initial-scale=1.0"
              />
              <meta httpEquiv="X-UA-Compatible" content="ie=edge" />

            </Head>
            <body>
              <Main />
              <NextScript />
              {/* Empty script tag as chrome bug fix, see https://stackoverflow.com/a/42969608/943337 */}
              <script> </script>
            </body>
          </html>
        );
      }
    }
  

Here we need to include an empty script element to prevent an issue on chrome browsers which causes the styling to be applied only once elements have been loaded in the DOM.

The readme in the GitHub project https://github.com/danownsthisspace/next-js-react-semantic-ui-custom-theme/blob/master/readme.md covers a bit on how to update the theme by overriding variables in the semantic/src/site folder, as well as how to compile the css file.