Framework-agnostic ClojureScript wrapper of Mantine. It works
from Fulcro, Reagent/re-frame, UIx, Helix, or raw React interop, and depends only on
react/createElement, never on a rendering framework. It wraps the complete Mantine
surface (generated from Mantine's docgen.json), and every factory's docstring carries the
component's Mantine.dev URL and full prop table, so you can read it from your editor or via
(clojure.repl/doc mc/button).
Available on Clojars as SNAPSHOT builds while the API settles. There is no stable release yet.
The wrapper exposes the full surface of ten @mantine/* packages: every component, hook,
and imperative API. Each package is a ClojureScript namespace; load the matching CSS yourself
(see Installation).
| Package | Namespace | CSS to import |
|---|---|---|
@mantine/core | mantine.core | @mantine/core/styles.layer.css (load first) |
@mantine/hooks | mantine.hooks | none |
@mantine/dates | mantine.dates | @mantine/dates/styles.layer.css · needs dayjs |
@mantine/charts | mantine.charts | @mantine/charts/styles.layer.css · needs recharts |
@mantine/notifications | mantine.notifications | @mantine/notifications/styles.layer.css |
@mantine/spotlight | mantine.spotlight | @mantine/spotlight/styles.layer.css |
@mantine/dropzone | mantine.dropzone | @mantine/dropzone/styles.layer.css |
@mantine/schedule | mantine.schedule | @mantine/schedule/styles.layer.css · needs @mantine/dates |
@mantine/modals | mantine.modals | none (styled by @mantine/core) |
@mantine/form | mantine.form | none (logic only) |
;; deps.edn
io.github.unisoma/mantine-ui-wrapper {:mvn/version "9.5.0.0-SNAPSHOT"}
Versions are <mantine-version>.N: the wrapped Mantine version plus a wrapper revision, so
the coordinate tells you exactly which Mantine you get (see
ADR 0001).
The jar ships deps.cljs (:npm-deps on @mantine/*), so shadow-cljs auto-installs the npm
packages. It does not declare react/react-dom: your app owns React. With other CLJS
tooling, install the npm deps manually:
npm install @mantine/core@^9.5.0 @mantine/hooks@^9.5.0 @mantine/notifications@^9.5.0 @mantine/modals@^9.5.0 @mantine/form@^9.5.0 @mantine/spotlight@^9.5.0 @mantine/dates@^9.5.0 @mantine/charts@^9.5.0 @mantine/dropzone@^9.5.0 @mantine/schedule@^9.5.0 dayjs@^1.11.21 recharts@^3.9.2 react react-dom
The wrapper imports no CSS. You load Mantine's stylesheets yourself, using the per-package files in the Coverage table. The rules:
.layer.css variant so your app's CSS wins regardless of import order.@mantine/core first, then the other packages.MantineProvider once at your app root.(:require ["@mantine/core/styles.css"]) does not work, because shadow
does not process CSS. <link> the files or run a CSS bundling step.Every component is a def in its package namespace, named in kebab-case (Button →
mantine.core/button, LineChart → mantine.charts/line-chart).
Conventions:
:left-section → leftSection).name (:size :sm → size: "sm", :position :top-start
→ "top-start" — values are never camelized), so keyword-style call sites work as they
do under clj->js-based wrappers.:styles, modal
:confirm-props, spotlight :actions, …) convert the same way at every depth.
Two opt-outs keep a value as untouched CLJS: :inner-props (handed raw to your
context modal) and (mantine.interop/no-convert v) for anything else.:data row fields (the paired
:data-key / :series strings are values and stay verbatim) and the
ModalsProvider :modals registry (looked up by open-context-modal's string
:modal). A kebab-case name there camelizes on one side only and silently
mismatches — the series plots nothing, the modal isn't found. Prefer dash-free
names (:sales, not :total-sales); to keep hyphens, pass the map raw with
(mantine.interop/no-convert (clj->js m)) or the :& escape hatch (plain clj->js, hyphens
preserved).:component ({:component "a" :href …}). To pass the
underlying Mantine component of another wrapper into such a slot (or for interop a
wrapper does not cover), use (mantine.interop/raw-component mc/anchor) — it returns
the raw React component from any wrapper var, reading through the controlled-input
shim so curated inputs (e.g. mc/text-input) yield the true component.notifications, modals, spotlight) expose both a provider and
call functions (mn/show, mm/open/mm/close, ms/toggle).def's docstring carries the Mantine.dev URL and full prop table.(ns my-app
(:require ["react" :as react]
["react-dom/client" :as rdom]
[mantine.core :as mc]
[mantine.hooks :as mh]
[mantine.notifications :as mn]))
(defn panel []
;; hooks return raw JS: a tuple here, destructured positionally
(let [[opened handlers] (mh/use-disclosure false)]
(mc/stack {:gap "md" :p "xl"}
(mc/button
{:color "teal"
:left-section "🔔"
:styles {:root {:font-weight 900}}
:on-click (fn [_] (mn/show {:title "It works" :message "Hello from Mantine"}))}
"Notify")
;; polymorphic component: renders an <a>
(mc/button {:component "a" :href "https://mantine.dev" :variant "outline"} "Docs")
(mc/button {:variant "light" :on-click (fn [_] (.toggle ^js handlers))}
(if opened "Hide" "Show"))
(mc/collapse {:expanded opened} (mc/text "Toggled content")))))
(defn app []
(mc/mantine-provider {}
(mn/provider {:position "top-right"}) ; imperative-API packages provide a provider
(react/createElement panel)))
(defn init []
(.render (rdom/createRoot (js/document.getElementById "app"))
(react/createElement app)))
A runnable sample of every pattern lives in
demo/mantine/demo.cljs.
MIT. See LICENSE. This project wraps Mantine, also MIT;
the generated docstrings come from Mantine's documentation.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |