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 docgen-generated factory's docstring
carries the component's full prop table, plus its Mantine.dev URL when it has a docs page, 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.7.0.0-SNAPSHOT"}
Versions are <anchor>.N: the Mantine anchor (the wrapped Mantine release) 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.7.0 @mantine/hooks@^9.7.0 @mantine/notifications@^9.7.0 @mantine/modals@^9.7.0 @mantine/form@^9.7.0 @mantine/spotlight@^9.7.0 @mantine/dates@^9.7.0 @mantine/charts@^9.7.0 @mantine/dropzone@^9.7.0 @mantine/schedule@^9.7.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 and are never camelized (:size :sm →
size: "sm", :position :top-start → "top-start"), 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, so the series plots nothing or 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 factory into such a slot (or for interop a
factory does not cover), use (mantine.interop/raw-component mc/anchor). It returns
the raw React component from any factory, 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).(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 |