shadcn/ui is popular but copy-paste only. Chakra UI is aging. Mantine gives you 100+ components, 60+ hooks, and a complete design system — all free, all maintained, all TypeScript-first.
What Makes Mantine Different
- 100+ components — from Button to RichTextEditor to DatePicker
- 60+ hooks — useForm, useClipboard, useIntersection, useHotkeys
- CSS-in-JS optional — works with any styling solution
- Dark mode — built-in, one prop to toggle
- Responsive — every component handles mobile
Setup
npm install @mantine/core @mantine/hooks
import { MantineProvider, Button } from "@mantine/core";
import "@mantine/core/styles.css";
function App() {
return (
<MantineProvider>
<Button variant="filled" color="blue">Click me</Button>
</MantineProvider>
);
}
Components Showcase
Forms
import { useForm } from "@mantine/form";
import { TextInput, NumberInput, Select, Button } from "@mantine/core";
function RegisterForm() {
const form = useForm({
initialValues: { name: "", email: "", age: 18, role: "" },
validate: {
name: (v) => v.length < 2 ? "Name too short" : null,
email: (v) => /^\S+@\S+$/.test(v) ? null : "Invalid email",
age: (v) => v < 18 ? "Must be 18+" : null,
},
});
return (
<form onSubmit={form.onSubmit(console.log)}>
<TextInput label="Name" {...form.getInputProps("name")} />
<TextInput label="Email" {...form.getInputProps("email")} />
<NumberInput label="Age" {...form.getInputProps("age")} />
<Select label="Role" data={["Developer", "Designer", "Manager"]} {...form.getInputProps("role")} />
<Button type="submit">Register</Button>
</form>
);
}
Data Table
import { Table, Badge, ActionIcon, Group } from "@mantine/core";
function UsersTable({ users }) {
return (
<Table striped highlightOnHover>
<Table.Thead>
<Table.Tr>
<Table.Th>Name</Table.Th>
<Table.Th>Role</Table.Th>
<Table.Th>Status</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>
{users.map(user => (
<Table.Tr key={user.id}>
<Table.Td>{user.name}</Table.Td>
<Table.Td>{user.role}</Table.Td>
<Table.Td>
<Badge color={user.active ? "green" : "gray"}>
{user.active ? "Active" : "Inactive"}
</Badge>
</Table.Td>
</Table.Tr>
))}
</Table.Tbody>
</Table>
);
}
Notifications
import { notifications } from "@mantine/notifications";
notifications.show({
title: "Order placed!",
message: "Your order #1234 has been confirmed",
color: "green",
autoClose: 5000,
});
60+ Hooks
import { useClipboard, useHotkeys, useMediaQuery, useIntersection, useLocalStorage } from "@mantine/hooks";
// Copy to clipboard
const clipboard = useClipboard({ timeout: 2000 });
clipboard.copy("Hello!");
// Keyboard shortcuts
useHotkeys([
["mod+S", () => saveDocument()],
["mod+K", () => openSearch()],
]);
// Responsive
const isMobile = useMediaQuery("(max-width: 768px)");
// Intersection observer
const { ref, entry } = useIntersection({ threshold: 0.5 });
// Local storage with type safety
const [theme, setTheme] = useLocalStorage({ key: "theme", defaultValue: "dark" });
Mantine vs Others
| Mantine | shadcn/ui | Chakra UI | MUI | |
|---|---|---|---|---|
| Components | 100+ | 40+ | 60+ | 80+ |
| Hooks | 60+ | 0 | 0 | 0 |
| Form library | Built-in | No | No | No |
| Bundle approach | npm package | Copy-paste | npm | npm |
| TypeScript | Native | Native | Good | Good |
| Theming | Excellent | Tailwind | Props | ThemeProvider |
Building React applications? I create web tools and data solutions. Email spinov001@gmail.com or explore my Apify tools.
Top comments (0)