Liking cljdoc? Tell your friends :D

mantine-ui-wrapper

Clojars Project cljdoc Mantine CI

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.

Coverage

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).

PackageNamespaceCSS to import
@mantine/coremantine.core@mantine/core/styles.layer.css (load first)
@mantine/hooksmantine.hooksnone
@mantine/datesmantine.dates@mantine/dates/styles.layer.css · needs dayjs
@mantine/chartsmantine.charts@mantine/charts/styles.layer.css · needs recharts
@mantine/notificationsmantine.notifications@mantine/notifications/styles.layer.css
@mantine/spotlightmantine.spotlight@mantine/spotlight/styles.layer.css
@mantine/dropzonemantine.dropzone@mantine/dropzone/styles.layer.css
@mantine/schedulemantine.schedule@mantine/schedule/styles.layer.css · needs @mantine/dates
@mantine/modalsmantine.modalsnone (styled by @mantine/core)
@mantine/formmantine.formnone (logic only)

Installation

;; 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

CSS

The wrapper imports no CSS. You load Mantine's stylesheets yourself, using the per-package files in the Coverage table. The rules:

  • Use the .layer.css variant so your app's CSS wins regardless of import order.
  • Load @mantine/core first, then the other packages.
  • Mount MantineProvider once at your app root.
  • Under shadow-cljs, (:require ["@mantine/core/styles.css"]) does not work, because shadow does not process CSS. <link> the files or run a CSS bundling step.

Usage

Every component is a def in its package namespace, named in kebab-case (Button → mantine.core/button, LineChart → mantine.charts/line-chart).

Conventions:

  • A factory takes an optional leading props map, then children.
  • Props are kebab-case keywords converted to camelCase (:left-section → leftSection).
  • Keyword prop values stringify via 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.
  • Conversion is deep by default: nested maps and vectors of maps (: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.
  • Conversion camelizes map keys everywhere, including in maps whose keys you name yourself. Two slots hold such maps: chart :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).
  • Hooks return raw JS, unconverted; destructure tuples positionally.
  • Polymorphic components accept :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.
  • Imperative packages (notifications, modals, spotlight) expose both a provider and call functions (mn/show, mm/open/mm/close, ms/toggle).
  • Every docgen-generated factory's docstring carries the full prop table, plus the Mantine.dev URL when the component has a docs page.
(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.

License

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

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close