Frontend developer focused on inclusive design

Next.js & Fluent UI: Setup

Before building a website using Next.js and Fluent UI, setup is required. In this guide, I share instructions on how to set up Fluent UI with Next.js.

Open VS Code

Visual Studio Code is a popular choice for writing code. However, any preferred code editor can be used. Just ensure the terminal is active.

Install Next.js

Ensure to enable the App Router feature during Next.js installation.

In terminal, run command:

npx create-next-app@latest

Fix parsing error (optional)

It's possible to experience the parsing error in Next.js when using ESLint. Page compiles, but first line of every JS file shows error:

Parsing error: Cannot find module 'next/babel' Require stack

To fix issue, locate .eslintrc.json in project. This file configures ESLint rules in a Next.js app, enhancing code quality and consistency.

In .eslintrc.json, locate the following code:

{
  "extends": "next/core-web-vitals"
}

Then, replace it with:

{
  "extends": ["next/babel","next/core-web-vitals"]
}

Install Fluent UI

In terminal, run command:

npm install @fluentui/react-components

Prepare project

By default, Next.js installs projects with sample code included.

In src folder, locate layout.js and update it:

// layout.js

import './globals.css'

export const metadata = {
  title: 'Next.js, Fluent UI and Me',
  description: 'My first website created with Next.js and Fluent UI',
}

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{ children }</body>
    </html>
  )
}

Then, update globals.css file:

/* globals.css */

* {
  box-sizing: border-box;
  padding: 0;
  margin: 0;
}

html,
body {
  max-width: 100vw;
  overflow-x: hidden;
}

Then, update page.js file:

// page.js

export default function Home() {
  return (
    <main className={ styles.main }>
      { console.log( 'Home page is loaded and ready to use.' ) }
    </main>
  )
}

Since, Home page will use Fluent UI styles, remove page.module.css file.

Start development

In terminal, run command:

npm run dev

The console shows URL to access a development website. Usually, URL is: http://localhost:3000

After refreshing the webpage, the VS Code terminal should display a message like:

Home page is loaded and ready to use.

This message comes from page.js file.

Integrate Fluent UI

Next.js' active App Router makes components React Server Components by default. Thus, Fluent UI requires additional configuration due to its extensive use of the React Context API.

React Context API isn't compatible with Server Components, as they lack state and effects support, focusing on data fetching and rendering.

Create Providers

This component is rendered near the root of application and helps to avoid createContext error.

Since Fluent UI (v9) heavily relies on React Context API, application must set use client directive for Fluent UI components.

To keep layout.js server-rendered, while still be able to use Fluent UI components, create providers.js file in root of project folder:

'use client';

// Import necessary dependencies from 'react'
import { useEffect, useState } from 'react'
// Import necessary dependencies from '@fluentui/react-components'
import {
  createDOMRenderer,
  RendererProvider,
  FluentProvider,
  webLightTheme,
  SSRProvider,
} from '@fluentui/react-components';

// Create a DOM renderer for Fluent UI.
const renderer = createDOMRenderer();

/**
 * Providers component.
 *
 * This component wraps other components with a set of providers
 * for Fluent UI, SSR, and a custom renderer.
 *
 * @param {Object} props - The properties for the Providers component.
 * @param {React.ReactNode} props.children - The child components to be wrapped by the Providers.
 * @returns {React.Element} The Providers component with child components.
 */
export function Providers({ children }) {
    // Declare a state variable named 'hasMounted' and a function named 'setHasMounted' to update it.
    const [ hasMounted, setHasMounted ] = useState(false);

    // Use the 'useEffect' hook to set 'hasMounted' to true once the component has mounted.
    useEffect(() => {
      setHasMounted(true);
    }, []);

    // If the component hasn't mounted yet, return nothing.
    if ( !hasMounted ) {
      return null;
    }

    // If the component has mounted, return a set of providers.
    return (
      <RendererProvider renderer={ renderer || createDOMRenderer() }>
        <SSRProvider>
          <FluentProvider theme={ webLightTheme }>
            { children }
          </FluentProvider>
        </SSRProvider>
      </RendererProvider>
    );
}

Integrate Providers

Providers must be used directly within application root.

Thus, open layout.js file and update it:

// layout.js

// Import global styles
import './globals.css'
// Import custom providers
import { Providers } from './providers';

/**
 * Metadata object for the website
 * @typedef {Object} metadata
 * @property {string} title - The title of the website
 * @property {string} description - A brief description of the website
 */
export const metadata = {
  title: 'Next.js, Fluent UI and Me',
  description: 'My first website created with Next.js and Fluent UI',
}

/**
 * RootLayout component
 * Wraps the entire application with the necessary providers
 *
 * @param {Object} props - Component properties
 * @param {React.ReactNode} props.children - Child elements to be wrapped by the RootLayout component
 * @returns {React.Element} The RootLayout component with the wrapped child elements
 */
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <Providers>{ children }</Providers>
      </body>
    </html>
  )
}

Build Home page

Time to build Home page layout with Fluent UI.

Open page.js file and update it:

'use client';

// Import necessary dependencies from '@fluentui/react-components'
import {
  makeStyles,
  shorthands,
  Text,
  Title1,
  tokens,
} from '@fluentui/react-components';

// Create a custom 'useStyles' hook to define the styling for the Home component.
const useStyles = makeStyles({
  container: {
    ...shorthands.padding( tokens.spacingHorizontalXXL ),
    ...shorthands.gap( tokens.spacingVerticalM ),
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
    justifyContent: 'center',
    minHeight: '100vh',
  },
});

/**
 * Home component.
 *
 * This component renders a simple 'Hello World!' message and
 * some text styled with Fluent UI components and utilities.
 *
 * @returns {React.Element} The Home component with the 'Hello World!' message and some text.
 */
export default function Home() {
  // Retrieve the styles object from the 'useStyles' hook.
  const styles = useStyles();

  // Render the Home component with a Title1 and Text component from Fluent UI.
  return (
    <main className={ styles.container }>
      <Title1 align="center">Hello World!</Title1>
      <Text>
        I am learning React and <strong>Fluent UI</strong>.
      </Text>
    </main>
  );
}

Now preview the changes. Open the development website in the browser. The page should display title and text, both using Fluent UI.

Preview code at Github