Introduction to Mantine UI Library

Necati Özmen - Dec 15 '23 - - Dev Community


refine repo


Author: Marvel Ken

Introduction

Mantine is a lightweight and easy-to-use library that provides a wide range of components and hooks for building high-performance web applications. It is built on top of React and TypeScript, making it a great choice for building modern web applications.

Setting Up Mantine UI

Mantine can be used with React,Refine, Next, Vite, Remix, and Gatsby.

In this article, we will be using Next. To install Mantine in a Next application follow the detailed steps below:

npx create-next-app@latest --typescript
Enter fullscreen mode Exit fullscreen mode

Mantine has a list of packages that can be used in your project this is what they look like:

mojo framework

By selecting anyone you could add them to the installation process:

npm install @mantine/core @mantine/hooks
Enter fullscreen mode Exit fullscreen mode

Now let's setup MantineProvider in our application:

Set up MantineProvider

In your Next.js application, you'll want to wrap your entire app with the MantineProvider component. You can do this by creating a _app.js file in your pages directory if it doesn't already exist, and then import MantineProvider and wrap your Component with it. Here's an example of what your _app.js file might look like:

import React from "react";
import { MantineProvider } from "@mantine/core";
import "../styles/globals.css"; // Import your global styles here

function MyApp({ Component, pageProps }) {
  return (
    <MantineProvider>
      <Component {...pageProps} />
    </MantineProvider>
  );
}

export default MyApp;
Enter fullscreen mode Exit fullscreen mode

Start Using Mantine Components

You can now start using Mantine components in your Next.js application. For example, create a new component in the components directory and use Mantine components inside it:

import React from "react";
import { Button } from "@mantine/core";

function MyComponent() {
  return <Button>Hello, Mantine!</Button>;
}

export default MyComponent;
Enter fullscreen mode Exit fullscreen mode

Then, import and use MyComponent in your pages:

import React from "react";
import MyComponent from "../components/MyComponent";

function Home() {
  return (
    <div>
      <h1>Welcome to My Next.js App with Mantine!</h1>
      <MyComponent />
    </div>
  );
}

export default Home;
Enter fullscreen mode Exit fullscreen mode

Run Your Next.js Application

Finally, run your Next.js application to see the Mantine components in action:

npm run dev
Enter fullscreen mode Exit fullscreen mode

Your Next.js application with Mantine is now set up and ready to go! You can continue to explore Mantine's Hooks and components and integrate them into your project as needed

Mantine UI Hooks

Hooks were introduced to change the way React components are built as they are meant to simplify component logic. They allow you to use state and other React features in functional components without writing a class. This makes the code cleaner and easier to understand.

With hooks, the logic can be reused (like fetching data or subscribing to external events) can be encapsulated in custom hooks. These custom hooks can be reused across different components and even different projects, promoting reusability.

Mantine as a React component Library utilizes custom hooks to manage state, manipulate the DOM, and handle design-related functionalities. These custom hooks are designed to simplify complex tasks, such as managing form state, handling user interactions, managing modals, and more.

Let’s explore a few of these hooks;

The useClipboard()

The useClipboard hook is a custom hook worth of mention. This hook simplifies working with the clipboard by providing an easy-to-use interface. It accepts an options argument, which defines the timeout duration (in milliseconds) for the copied status. If the copy function is called within the specified timeout, the copied value will be true, indicating that the copy operation was successful within that timeframe.

Here's the TypeScript definition of the useClipboard hook for reference:

function useClipboard(options: { timeout: number } = { timeout: 2000 }): {
  copy: (valueToCopy: any) => void;
  reset: () => void;
  error: Error;
  copied: boolean;
};
Enter fullscreen mode Exit fullscreen mode

Here's a breakdown of the properties returned by the useClipboard() hook:
copy: (valueToCopy: any) => void: This is a function that you can call with the value you want to copy to the clipboard. For example, if you want to copy a string, you would call copy('text to copy').

reset: () => void: This function clears the timeout and resets the copied value. You can use this function if you want to reset the copied status manually.

error: Error: This property contains an Error object if something goes wrong during the copying process. For example, if the browser does not support the clipboard API or if there are other issues, the error property will be populated with an error object.

copied: boolean: This property is a boolean value that indicates whether the copy function was called less than options.timeout milliseconds ago. If it was, copied is true; otherwise, it is false. This property is useful for showing feedback to the user, such as displaying a message like "Copied!" after a successful copy operation.

Let’s use this hook to simplify clipboard interactions in our React application:

import React from "react";
import { useClipboard } from "@mantine/hooks";

import FileCopyIcon from "@mui/icons-material/FileCopy";

const App: React.FC = () => {
  const items = ["https://refine.dev/blog/"];
  const clipboard = useClipboard({ timeout: 1500 });
  return (
    <div>
      <ul>
        {items.map((description, index) => (
          <li key={index}>
            <button onClick={() => clipboard.copy(description)}>
              {clipboard.copied ? <span>Copied! </span> : <span>Copy Link </span>}
              <FileCopyIcon />
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

let's take a look at what it looks like:

mojo framework

UseWindowScroll()

Building a web page involves making it as interactive as possible and making ease of use a top priority. If you are conversant with blogs, especially those bulky ones, where you must have scrolled a lot and you just want to go back to the top of the web page, scrolling backup becomes stressful.

As developers, we prioritize enhancing user experience, and this is where the useWindowScroll() hook comes into play. This hook seamlessly interacts with the DOM, providing access to the current scroll position and enabling smooth scrolling to a specific location on the page.

This is what the actual implementation looks like:

import { useWindowScroll } from "@mantine/hooks";
import { Button, Text, Group } from "@mantine/core";

export default function App() {
  const [scroll, scrollTo] = useWindowScroll();

  return (
    <Group className="center">
      <Button onClick={() => scrollTo({ y: document.body.scrollHeight })}>Scroll to Bottom</Button>
      <Text>//Long Text</Text>
      <Button onClick={() => scrollTo({ y: 0 })}>Scroll to top</Button>
    </Group>
  );
}
Enter fullscreen mode Exit fullscreen mode

Use-Disclosure

The useDisclosure() hook is our last tool on the list and it deserves recognition. useDisclosure() simplifies managing boolean state in React applications. It's particularly useful for handling components like modals, popovers, and other UI elements that need to be conditionally displayed or hidden based on user interactions.

Open, Close, and Toggle Handlers hooks provide intuitive open(), close(), and toggle() handlers. These functions abstract away the complexities of managing state transitions, making it easier to control when a component should be displayed or hidden.

The hook accepts optional onOpen and onClose callbacks. These callbacks enable you to execute specific actions or logic when the component is opened or closed. For instance, you could perform additional tasks or trigger animations when a modal opens or closes.

Let’s look at how this is implemented:

import React from "react";
import { useDisclosure } from "@mantine/hooks";
import { Modal, Button, Group, Col, Container } from "@mantine/core";

export default function App() {
  const [opened, { open, close }] = useDisclosure(false);

  return (
    <div>
      <Modal opened={opened} onClose={close} title="We use cookies" centered size="sm">
        <p>This website uses cookies to ensure you get the best experience on our website.</p>
        <Container mt={4}>
          <Group position="right">
            <Button color="gray" onClick={close}>
              Decline
            </Button>
            <Button variant="filled" color="blue" onClick={close}>
              Accept
            </Button>
          </Group>
        </Container>
      </Modal>
      <Button onClick={open}>Click here to advance</Button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

let's take a look at what it looks like:

mojo framework

Why Mantine UI?

Browser Support and Compatibility

Mantine dedicatedly ensures compatibility and functionality across major browsers, including Chrome, Safari, Firefox, Edge, Safari for iOS, and Chrome for Android. Components and hooks are tested and optimized for Chromium browsers (version 108+), Firefox (version 101+), and Safari (version 15.4+).

While older versions like IE are unsupported, Mantine seamlessly integrates with React versions, ensuring broad compatibility. For older browser support, users can refer to specific component documentation and implement necessary polyfills.

Reliable Release Cycle and Community-Driven Development

Mantine follows a clear plan when it's updated, making it stable and reliable. They make small improvements every month in minor updates, and bigger changes happen less often in major updates.

What's great is that many people help make Mantine better - over 300 contributors are part of this community effort! Mantine UI isn't just a library; it's a vibrant ecosystem where user experience meets innovation.

User-Friendly Components

Mantine provides a large range of user-friendly components that are very easy to implement. Whether you need buttons, forms, modals, or navigation elements, Mantine's components are developer-friendly, making the development process smooth and easy.

Performance Optimization

Mantine’s components are lightweight, ensuring fast loading times and smooth user interactions. This makes it an excellent choice for building high-performance web applications.

Customization and Theming

Mantine offers extensive customization options. You can easily customize the appearance of components to match your brand identity. With theming support, you can create consistent and visually appealing designs across your entire application.

Mantine UI Components

Mantine as a UI library simplifies the development process with the use of inbuilt easy-to-use components. We will explore the core aspects of Mantine's UI components, providing an overview of the available components and diving into some of its flagship elements which are: Forms and Inputs, Navigation, Notifications, Modals, and Theming.

Mantine offers a wide array of components that cater to various UI requirements. Some of the core components include:

Forms and Inputs:

- **Text Input:** Allows users to input text data.
- **Textarea:** Provides a multi-line text input field.
- **Select:** A dropdown menu for selecting options.
- **Radio:** A set of radio buttons for single-choice selection.
- **Checkbox:** Checkboxes for multiple-choice selection.
- **Form:** A container for grouping and handling form elements.
Enter fullscreen mode Exit fullscreen mode

Navigation:

- **Tabs:** Horizontal navigation tabs for switching between content.
- **Breadcrumbs:** Indicates the current page's location within the website hierarchy.
- **Menu:** A dropdown menu for navigation or actions.
Enter fullscreen mode Exit fullscreen mode

Notifications and Modals:

- **Notifications:** Provides feedback messages to users.
- **Modals:** Dialog boxes or pop-ups for interactive user input or messages.
- **Popover:** A small overlay for additional information or actions.
- **Tooltip:** Displays additional information when hovering over an element.
Enter fullscreen mode Exit fullscreen mode

Data Display:

- **Avatar:** Displays profile pictures or avatars.
- **Badge:** Small containers to highlight certain information.
- **Card:** Container component for displaying various types of content.
- **Table:** Displays data in a tabular format.
- **List:** Renders a list of items.
- **Typography:** Includes various text styles, headings, and paragraphs.
Enter fullscreen mode Exit fullscreen mode

Utilities:

- **Col:** Defines a column layout within a grid.
- **Row:** Defines a row layout within a grid.
- **Container:** A responsive container for managing layout width.
- **Image:** Displays images with various customization options.
Enter fullscreen mode Exit fullscreen mode

Exploring the Use Case of Mantine Component

In this section, we will be looking at the various implementations of the Mantine components and how they can be utilized in our projects.

Forms and Inputs

Mantine's form components are designed for ease of use and customization. For instance, the TextInput component allows developers to create input fields with various styles, validations, and placeholder texts. The Form component simplifies form management, elegantly handling form submissions, validations, and error messages.

import { TextInput, Checkbox, Button, Group, Box } from "@mantine/core";
import { useForm } from "@mantine/form";

function App() {
  const form = useForm({
    initialValues: {
      email: "",
      termsOfService: false,
    },
    validate: {
      email: (value) => (/^\S+@\S+$/.test(value) ? null : "Invalid email"),
    },
  });

  return (
    <Box maw={340} mx="auto">
      <form onSubmit={form.onSubmit((values) => console.log(values))}>
        <TextInput
          withAsterisk
          label="Email"
          placeholder="please provide your valid @email.com"
          {...form.getInputProps("email")}
        />
        <Checkbox
          mt="md"
          label="I agree to read Refine's Blog always"
          {...form.getInputProps("termsOfService", { type: "checkbox" })}
        />
        <Group justify="flex-end" mt="md">
          <Button type="submit">Submit</Button>
        </Group>
      </form>
    </Box>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

mojo framework

Navigation:
Mantine offers various navigation components, such as Menu, Tab, and Pagination, enhancing the user experience. Tabs enable organized content switching, while Paginations Display active pages and navigate between multiple pages. Menus and Dropdowns simplify complex navigational hierarchies.

import { Tabs } from "@mantine/core";

function App() {
  return (
    <Tabs defaultValue="first">
      <Tabs.List>
        <Tabs.Tab value="first" color="blue">
          Refine Blog
        </Tabs.Tab>
        <Tabs.Tab value="second" color="red">
          Refine Pricing
        </Tabs.Tab>
        <Tabs.Tab value="third" color="green">
          Refine Community
        </Tabs.Tab>
        <Tabs.Tab value="fourth" color="yellow">
          Refine Open Source
        </Tabs.Tab>
      </Tabs.List>
    </Tabs>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

mojo framework
import { Pagination } from "@mantine/core";

export default function App() {
  return <Pagination total={36} />;
}
Enter fullscreen mode Exit fullscreen mode
import { Menu, Button, Text, rem } from "@mantine/core";
import {
  IconSettings,
  IconSearch,
  IconPhoto,
  IconMessageCircle,
  IconTrash,
  IconArrowsLeftRight,
} from "@tabler/icons-react";

export default function App() {
  return (
    <Menu shadow="md" width={200}>
      <Menu.Target>
        <Button>Main menu</Button>
      </Menu.Target>
      <Menu.Dropdown>
        <Menu.Label>Application</Menu.Label>
        <Menu.Item leftSection={<IconSettings style={{ width: rem(14), height: rem(14) }} />}>blog</Menu.Item>
        <Menu.Item leftSection={<IconMessageCircle style={{ width: rem(14), height: rem(14) }} />}>Pricing</Menu.Item>
        <Menu.Item color="red" leftSection={<IconPhoto style={{ width: rem(14), height: rem(14) }} />}>
          Github
        </Menu.Item>
        <Menu.Item leftSection={<IconSearch style={{ width: rem(14), height: rem(14) }} />}>Search</Menu.Item>
        <Menu.Divider />
      </Menu.Dropdown>
    </Menu>
  );
}
Enter fullscreen mode Exit fullscreen mode

mojo framework

Notifications
Mantine's notifications and modals provide user feedback and interactive dialogues. Notifications offer informative or alerting messages to users, while modals and popovers facilitate interactive tasks, ensuring a seamless user experience. Let’s look at how this is implemented below:

import { IconX, IconCheck } from "@tabler/icons-react";
import { Notification, rem } from "@mantine/core";

function App() {
  const xIcon = <IconX style={{ width: rem(20), height: rem(20) }} />;
  const checkIcon = <IconCheck style={{ width: rem(20), height: rem(20) }} />;

  return (
    <>
      <Notification icon={xIcon} color="blue" title="Hey!">
        Got to Refine immediately
      </Notification>
      <Notification icon={checkIcon} color="teal" title="All good!" mt="md">
        Everything should be fine!!
      </Notification>
    </>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

mojo framework
import { useDisclosure } from "@mantine/hooks";
import { Modal, Button } from "@mantine/core";
import { TextInput, Checkbox, Group, Box } from "@mantine/core";
import { useForm } from "@mantine/form";

export default function App() {
  const [opened, { open, close }] = useDisclosure(false);

  const form = useForm({
    initialValues: {
      email: "",
      termsOfService: false,
    },
    validate: {
      email: (value) => (/^\S+@\S+$/.test(value) ? null : "Invalid email"),
    },
  });

  return (
    <>
      <Modal opened={opened} onClose={close} title="Refine form" centered>
        <Box maw={340} mx="auto">
          <form onSubmit={form.onSubmit((values) => console.log(values))}>
            <TextInput
              withAsterisk
              label="Email"
              placeholder="please provide your valid @email.com"
              {...form.getInputProps("email")}
            />
            <Checkbox
              mt="md"
              label="I agree to read Refine's Blog always"
              {...form.getInputProps("termsOfService", { type: "checkbox" })}
            />
            <Group>
              <Button className="BTN" onClick={close} type="submit">
                Submit
              </Button>
            </Group>
          </form>
        </Box>
      </Modal>
      <Button onClick={open}>Open centered Modal</Button>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

mojo framework

Theming and Customization
Mantine allows extensive theming and customization, allowing developers to align the UI with the brand identity. The MantineProvider component wraps the entire application, providing a context for theme customization. Themes include color schemes, typography, spacing, and other design elements, enabling a consistent look and feel across components.

import { MantineProvider, Container, TextInput } from "@mantine/core";

function App() {
  return (
    <MantineProvider theme={{ colorScheme: "dark" }}>
      <Container>
        <TextInput label="Dark Mode Input" placeholder="Enter text" />
      </Container>
    </MantineProvider>
  );
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

In the fast-paced world of web development, as web developers, we only have a limited time to deliver tasks unless it’s a personal project for which a deadline is a good practice. having tools that will help meet deadlines and also help in producing visually appealing interfaces is detrimental. Mantine has proven to be one of the go-to UI libraries for this.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .