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

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

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 (Buttonmantine.core/button, LineChartmantine.charts/line-chart).

Conventions:

  • A factory takes an optional leading props map, then children.
  • Props are kebab-case keywords converted to camelCase (:left-sectionleftSection).
  • Keyword prop values stringify via name (:size :smsize: "sm", :position :top-start"top-start" — values are never camelized), 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 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 — 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).
  • Hooks return raw JS, unconverted; destructure tuples positionally.
  • Polymorphic components accept :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.
  • Imperative packages (notifications, modals, spotlight) expose both a provider and call functions (mn/show, mm/open/mm/close, ms/toggle).
  • Every 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.

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