How to use the Mantine library with the nextjs 13?
How to use the Mantine library with the nextjs 13?

Nextjs + Mantine

How to use the Mantine library with the nextjs 13?

Design a Modern website with Mantine UI and Hooks.

Rajdeep singh
FrontEnd web
Published in
9 min readMay 3

--

I used so many UI component libraries in my past life as a front-end developer. Last Time I was impressed with Github Primer, and I never did something like that. But recently found one more library that changes my life. It provides many features out of the box, and no other library provides that. The Libaray name is Mantine. Mantine is more suitable for all kinds of small and large-scale websites.

Some of the cool features which I like are that is

  1. 55 Ready-made react hooks
  2. 134 Ready-made components
  3. Inbuilt form handling and design
  4. Inbuilt date and time handling

Investing Time into learning Mantine Library is a good approach. For large-scale websites, one UI library does not solve all problems. But the other hand Mantine UI library provides modern components, for example, Prism code highlight, spotlight, dropzone, TypographyStylesProvider, etc.

Inbuilt Mantine Hook solves every problem related to your project. Mantine provides a bunch of hooks, for example, pagination handling, Toggle, use-input-state, etc

All the code is available on GitHub. You can also check out the live demo website.

Let’s start

· Setup new Nextjs Project
· Installation
Mantine Packages List
· Configuration
· How to enable the theme toggle in mantine?
· How to build the Header with mentine?
· Conclusion

Setup new Nextjs Project

The first step is to create a new nextjs application or project with create-next-app to start work with the Matine UI library.

To create a new nextjs app, run the following command and install the tailwind css and typescript.

npx create-next-app@latest
# or
yarn create next-app
# or
pnpm create next-app
rajdeepsingh@officialrajdeepsingh:~/open-sources$ pnpm create next-app@latest
.../share/pnpm/store/v3/tmp/dlx-344317 | +1 +
Packages are hard linked from the content-addressable store to the virtual store.
Content-addressable store is at: /home/rajdeepsingh/.local/share/pnpm/store/v3
Virtual store is at: ../.local/share/pnpm/store/v3/tmp/dlx-344317/node_modules/.pnpm
.../share/pnpm/store/v3/tmp/dlx-344317 | Progress: resolved 1, reused 0, downloaded 1, added 1, done
✔ What is your project named? … mantine-ui-nextjs
✔ Would you like to use TypeScript with this project? … No / Yes
✔ Would you like to use ESLint with this project? … No / Yes
✔ Would you like to use Tailwind CSS with this project? … No / Yes
✔ Would you like to use `src/` directory with this project? … No / Yes
✔ Would you like to use experimental `app/` directory with this project? … No / Yes
✔ What import alias would you like configured? … @/*
Creating a new Next.js app in /home/rajdeepsingh/open-sources/mantine-ui-nextjs.

Using pnpm.

Initializing project with template: app-tw


Installing dependencies:
- react
- react-dom
- next
- typescript
- @types/react
- @types/node
- @types/react-dom
- tailwindcss
- postcss
- autoprefixer
- eslint
- eslint-config-next

Packages: +322
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Packages are hard linked from the content-addressable store to the virtual store.
Content-addressable store is at: /home/rajdeepsingh/.local/share/pnpm/store/v3
Virtual store is at: node_modules/.pnpm
Downloading registry.npmjs.org/next/13.3.2: 12.1 MB/12.1 MB, done
Downloading registry.npmjs.org/@next/swc-linux-x64-musl/13.3.2: 37.8 MB/37.8 MB, done
Downloading registry.npmjs.org/@next/swc-linux-x64-gnu/13.3.2: 37.9 MB/37.9 MB, done
Progress: resolved 330, reused 303, downloaded 19, added 322, done

dependencies:
+ @types/node 18.16.3
+ @types/react 18.2.0
+ @types/react-dom 18.2.1
+ autoprefixer 10.4.14
+ eslint 8.39.0
+ eslint-config-next 13.3.2
+ next 13.3.2
+ postcss 8.4.23
+ react 18.2.0
+ react-dom 18.2.0
+ tailwindcss 3.3.2
+ typescript 5.0.4

The integrity of 4210 files was checked. This might have caused installation to take longer.
Done in 7m 42.8s
Initialized a git repository.

Success! Created mantine-ui-nextjs at /home/rajdeepsingh/open-sources/mantine-ui-nextjs

rajdeepsingh@officialrajdeepsingh:~/open-sources$

I choose tailwind CSS to speed up the design process with nextjs and Mantine UI library.

Installation

The entire Mantine UI library divides into packages, and developers easily install Mantine packages according to their requirements.

Mantine Packages List

  1. @mantine/hooks: Hooks for state and UI management
  2. @mantine/core: Core components library: inputs, buttons, overlays, etc.
  3. @mantine/form: Form management library.
  4. @mantine/dates: Date inputs, calendars
  5. @mantine/notifications: Notifications system
  6. @mantine/prism: Code highlight with your theme colors and styles
  7. @mantine/tiptap: Rich text editor based on Tiptap
  8. @mantine/dropzone: Capture files with drag and drop
  9. @mantine/carousel: Embla-based carousel component
  10. @mantine/spotlight: The overlay command with command + k.
  11. @mantine/modals: Centralized models manager
  12. @mantine/nprogress: Navigation progress

Due to the different package varieties, Mantine provides an installation page where you select and remove the package and convert them into one command.

For Nextjs, to start work with mantine, you need the following compulsory package to install in your project.

yarn add @mantine/core @mantine/hooks @mantine/next @emotion/server @emotion/react

# or

yarn add @mantine/core @mantine/hooks @mantine/next @emotion/server @emotion/react

# or

yarn add @mantine/core @mantine/hooks @mantine/next @emotion/server @emotion/react

Configuration

Configuring the mantine UI library with nextjs is a straightforward process, just like a copy-paste of code.

Replace your existing _document.tsx file code with the following code.

// _document.tsx copy and paste

import { createGetInitialProps } from '@mantine/next';
import Document, { Head, Html, Main, NextScript } from 'next/document';

const getInitialProps = createGetInitialProps();

export default class _Document extends Document {
static getInitialProps = getInitialProps;

render() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}

Replace your current _app.tsx code with the following code.

// _app.tsx

import { AppProps } from 'next/app';
import Head from 'next/head';
import { MantineProvider } from '@mantine/core';

export default function App(props: AppProps) {
const { Component, pageProps } = props;

return (
<MantineProvider
withGlobalStyles
withNormalizeCSS
theme={{
/** Put your mantine theme override here light or dark theme */
colorScheme: 'light',
}}
>
<Component {...pageProps} />
</MantineProvider>

);
}

Now the configuration part is done. To test your nextjs app, copy and paste the following code into your index.tsx file.

// pages/index.tsx

import Head from "next/head";
import { Box, Center, Container } from "@mantine/core";
export default function Home() {
return (
<>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<Container className="box">
<Center h={724} mx="auto">
<Box>All elements inside Center are centered in Container.</Box>
</Center>
</Container>
</>
);
}

Change the background color. I write some css in the `globals.css` file.

Your nextjs demo app looks like in a browser to run a local development server with npm run dev .

Demo app

How to enable the theme toggle in mantine?

To create a theme toggle with mantine, you need to change some code in _app.tsx file.

// import Tailwind CSS file
import '@/styles/globals.css';

import type { AppProps } from 'next/app';
import { useLocalStorage } from '@mantine/hooks';

// ColorSchemeProvider help to enable toggle
import { MantineProvider, ColorSchemeProvider, ColorScheme } from '@mantine/core';

export default function App({ Component, pageProps }: AppProps) {

// set theme in local store
const [colorScheme, setColorScheme] = useLocalStorage<ColorScheme>({
key: 'demo-color-scheme',
defaultValue: 'light',
getInitialValueInEffect: true,
});

// create theme toggle
const toggleColorScheme = (value?: ColorScheme) => setColorScheme(value || (colorScheme === 'dark' ? 'light' : 'dark'));


return (
<ColorSchemeProvider colorScheme={colorScheme} toggleColorScheme={toggleColorScheme}>
<MantineProvider withGlobalStyles withNormalizeCSS theme={{ colorScheme }}>

<Component {...pageProps} />
</MantineProvider>
</ColorSchemeProvider>
)
}

To toggle the theme from light to dark, you need to use the useMantineColorSchemehook import from the @mantine/core package.

import { createStyles, Header, Group, ActionIcon, Container, Burger, rem } from '@mantine/core';

// import icons from @tabler/icons-react
import { IconBrandTwitter, IconBrandLinkedin, IconBrandGithub, IconSun, IconMoonStars } from '@tabler/icons-react';

// import useMantineColorScheme hook to toggle theme
import { useMantineColorScheme } from '@mantine/core';

import Link from 'next/link';


const useStyles = createStyles((theme) => ({
// some css
})));

interface HeaderMiddleProps {
links: { link: string; label: string }[];
}

export function HeaderMenu({ links }: HeaderMiddleProps) {

const { classes, cx } = useStyles();

// toggle theme between light and dark

const { colorScheme, toggleColorScheme } = useMantineColorScheme();

const dark = colorScheme === 'dark';



return (
<Header height={56} mb={120}>
<Container className={classes.inner}>

<Group position='center'>

{/* ... rest of code */}

<Group spacing={0} className={classes.social} position="center" noWrap>

{/* ... rest of code */}

<Link target='_blank' href="https://twitter.com/Official_R_deep">
<ActionIcon size="lg">
<IconBrandTwitter size="1.1rem" stroke={1.5} />
</ActionIcon>
</Link>

<Link target='_blank' href="https://www.linkedin.com/in/officalrajdeepsingh/">
<ActionIcon size="lg">
<IconBrandLinkedin size="1.1rem" stroke={1.5} />
</ActionIcon>
</Link>

<Link target='_blank' href="http://github.com/officialrajdeepsingh">
<ActionIcon size="lg">
<IconBrandGithub size="1.1rem" stroke={1.5} />
</ActionIcon>
</Link>

<SearchBar />

{/* Theme toggling and changing icon */}

<ActionIcon
size="lg"
variant="outline"
color={dark ? 'yellow' : 'blue'}
onClick={() => toggleColorScheme()}
title="Toggle color scheme"
>
{dark ? <IconSun size="1.1rem" /> : <IconMoonStars size="1.1rem" />}
</ActionIcon>
</Group>
</Group>
</Container>
</Header>
);
}

How to build the Header with mentine?

The Mantine provides inbuilt, ready-made open-source 134 responsive components.

Header

Then I click the Headers section.

choose Header

Select one of the header components which are you like for the site. Then copy the code and paste it into your file.

// Header.tsx

import { useState } from 'react';
import { createStyles, Header, Group, ActionIcon, Container, Burger, rem } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { IconBrandTwitter, IconBrandYoutube, IconBrandInstagram } from '@tabler/icons-react';
import { MantineLogo } from '@mantine/ds';

const useStyles = createStyles((theme) => ({
inner: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
height: rem(56),

[theme.fn.smallerThan('sm')]: {
justifyContent: 'flex-start',
},
},

links: {
width: rem(260),

[theme.fn.smallerThan('sm')]: {
display: 'none',
},
},

social: {
width: rem(260),

[theme.fn.smallerThan('sm')]: {
width: 'auto',
marginLeft: 'auto',
},
},

burger: {
marginRight: theme.spacing.md,

[theme.fn.largerThan('sm')]: {
display: 'none',
},
},

link: {
display: 'block',
lineHeight: 1,
padding: `${rem(8)} ${rem(12)}`,
borderRadius: theme.radius.sm,
textDecoration: 'none',
color: theme.colorScheme === 'dark' ? theme.colors.dark[0] : theme.colors.gray[7],
fontSize: theme.fontSizes.sm,
fontWeight: 500,

'&:hover': {
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[0],
},
},

linkActive: {
'&, &:hover': {
backgroundColor: theme.fn.variant({ variant: 'light', color: theme.primaryColor }).background,
color: theme.fn.variant({ variant: 'light', color: theme.primaryColor }).color,
},
},
}));

interface HeaderMiddleProps {
links: { link: string; label: string }[];
}

export function HeaderMiddle({ links }: HeaderMiddleProps) {
const [opened, { toggle }] = useDisclosure(false);
const [active, setActive] = useState(links[0].link);
const { classes, cx } = useStyles();

const items = links.map((link) => (
<a
key={link.label}
href={link.link}
className={cx(classes.link, { [classes.linkActive]: active === link.link })}
onClick={(event) => {
event.preventDefault();
setActive(link.link);
}}
>
{link.label}
</a>
));

return (
<Header height={56} mb={120}>
<Container className={classes.inner}>
<Burger opened={opened} onClick={toggle} size="sm" className={classes.burger} />
<Group className={classes.links} spacing={5}>
{items}
</Group>

<MantineLogo size={28} />

<Group spacing={0} className={classes.social} position="right" noWrap>
<ActionIcon size="lg">
<IconBrandTwitter size="1.1rem" stroke={1.5} />
</ActionIcon>
<ActionIcon size="lg">
<IconBrandYoutube size="1.1rem" stroke={1.5} />
</ActionIcon>
<ActionIcon size="lg">
<IconBrandInstagram size="1.1rem" stroke={1.5} />
</ActionIcon>
</Group>
</Container>
</Header>
);
}

Then import your Header on _app.tsx or your layout file. Then use it.


import '@/styles/globals.css';
import type { AppProps } from 'next/app';
import { useLocalStorage } from '@mantine/hooks';
import { MantineProvider, ColorSchemeProvider, ColorScheme } from '@mantine/core';

// Import Header component
import { HeaderMiddle } from '@/components/Header/Header';

let links = [ { link: "/", label: "Home" }, { link: "/about", label: "About us" }, { link: "/contact", label: "Contact us" }];

export default function App({ Component, pageProps }: AppProps) {
const [colorScheme, setColorScheme] = useLocalStorage<ColorScheme>({
key: 'demo-color-scheme',
defaultValue: 'light',
getInitialValueInEffect: true,
});

const toggleColorScheme = (value?: ColorScheme) => setColorScheme(value || (colorScheme === 'dark' ? 'light' : 'dark'));

return (
<ColorSchemeProvider colorScheme={colorScheme} toggleColorScheme={toggleColorScheme}>
<MantineProvider withGlobalStyles withNormalizeCSS theme={{ colorScheme }}>

{/* Use it and nav links */}
<HeaderMiddle links={links} />

<Component {...pageProps} />

</MantineProvider>
</ColorSchemeProvider>
)
}

Note

Currently, Mantine is not ready for the nextjs app directory.

Conclusion

Mantine is an excellent library for building small to large-scale websites with nextjs. It speeds up the development process and provides a modern look similar to the MUI library.

I promise if you use the Mantine library, you never need any other UI library and packages for the site.

You can use Tailwind CSS with mantine. But you can’t utilize Tailwind CSS dark mode darkMode:”class” class-based functionality. You can only use darkMode:”media” functionality.

You can share and follow us on Twitter and Linkedin. If you like my work, please read more content on the officialrajdeepsingh.dev, frontend web, and Sign up for a free newsletter.

You can also check out awesome-next, a curated list of awesome Nextjs-based libraries that help build small and large-scale applications with next.js.

--

--

Rajdeep singh
FrontEnd web

JavaScript || Reactjs || Nextjs || Python || Rust || Biotechnology || Bioinformatic || Front-end Developer || Author https://officialrajdeepsingh.dev/

Recommended from Medium

Lists

See more recommendations