@moontra/moonui-pro
v4.28.0
Published
Premium React components for MoonUI - Advanced UI library with 50+ pro components including performance, interactive, and gesture components
Downloads
11,629
Maintainers
Readme
MoonUI Pro 🌙✨
Premium React components for advanced web applications. MoonUI Pro extends the base MoonUI library with sophisticated, enterprise-grade components designed for complex use cases and professional applications.
Two setups, both mandatory. Styling setup makes the components look right — skip it and they render shapeless and colourless. License setup makes them work — without a build-time license token, Pro components render a lock screen instead of their content.
✨ What's Included
A selection of what ships in the package. The full, always-current component list lives at moonui.dev/docs.
📊 Data & Analytics
DataTable— Enterprise table with search, faceted/quick filters, export, row selection, expandable rows and bulk actionsTable— Lower-level styled table primitivesAdvancedChart,ChartWidget— Data visualization built on RechartsTimeline— Event timelines with rich contentKanban— Drag-and-drop board layouts
✏️ Editors & Forms
RichTextEditor— WYSIWYG editorFormWizard— Multi-step forms with validation and progress trackingColorPicker— Color selection
🎮 Interactive & Gesture
DraggableList— Sortable lists with smooth animationsSwipeableCard— Touch-friendly cardsGestureDrawer— Mobile-optimized drawer with gesturesVirtualList,SelectableVirtualList— High-performance virtualized listsLazyList,AnimatedList— Lazy and animated list rendering
📅 Calendar
Calendar,AdvancedCalendar— Date selection and event calendars
🎨 Visual & Motion
BentoGrid— Modern bento-style layoutsSpotlight— Search and command launcherParallaxScroll,ScrollReveal— Scroll-driven effectsGridPattern,GridDistortion— Decorative backgroundsMarquee,Meteors— Motion accentsLightboxProvider— Image lightbox
🔤 Text Effects
GlitchText,ShinyText,TextReveal,Text3D
🚀 Installation
npm install @moontra/moonui-pro @moontra/moonui
# Tailwind is required; the components also use the animate plugin
npm install -D tailwindcss tailwindcss-animateWhy @moontra/moonui is in that line. Pro ships its own React primitives
(Button, Card, Badge, Input, …), so you do not need the free package for its
components. You do need it for its design system: the only copy of the Tailwind
preset and of the CSS variables the Pro components paint with lives there. Between its
inline styles and its Tailwind classes, Pro needs 51 theme variables (--primary,
--card, --secondary-500, --info-subtle, …) and defines none of them. Install Pro
on its own and every bg-primary resolves to transparent and every text-foreground
to plain black — see Styling setup.
The free package is MIT-licensed, and using its components is still optional.
🎨 Styling setup
All three steps are required. Skip step 1 and the utility classes are never generated; skip step 2 and they are generated but every colour resolves to nothing; skip step 3 and the Radix-driven enter/exit animations are missing.
1. Add the Tailwind preset
The preset maps Tailwind's colour, radius and animation scales onto MoonUI's CSS
variables. The content entry for Pro's dist/** matters just as much: Tailwind only
generates classes it can see, and the Pro component classes live inside the package
bundle.
// tailwind.config.js (Tailwind v3 config format)
module.exports = {
presets: [require("@moontra/moonui/tailwind-preset")],
content: [
"./src/**/*.{js,ts,jsx,tsx,mdx}",
"./node_modules/@moontra/moonui-pro/dist/**/*.{js,mjs}",
// only if you also use the free components:
"./node_modules/@moontra/moonui/dist/**/*.{js,mjs}",
],
plugins: [require("tailwindcss-animate")],
};If your
package.jsonhas"type": "module", name the filetailwind.config.cjs. Left as.js, Node parses it as ESM and themodule.exportsabove throwsReferenceError: module is not definedbefore Tailwind ever sees your config.
There is no separate Pro preset — @moontra/moonui/tailwind-preset is a superset of
everything Pro needs. It declares every colour key Pro uses (primary, secondary,
success, warning, caution, error, info, destructive, muted, accent,
card, popover, border, input, ring, background, foreground) plus
brand/brand-accent, and it already sets darkMode: "class".
2. Import the design tokens
The preset only maps the variables; this file defines them, for both light and dark.
/* globals.css */
@import "@moontra/moonui/src/styles/tokens.css";
@tailwind base;
@tailwind components;
@tailwind utilities;Which specifier, and why they differ. CSS
@importand JavaScriptimportare resolved by different machinery, and the two want different strings:| Where you write it | Specifier that works | |---|---| | CSS
@import, Tailwind v3 + PostCSS (postcss-import) |@moontra/moonui/src/styles/tokens.css| | CSS@import, Vite (its resolver readsexports) |@moontra/moonui/tokens.css| | JavaScriptimport(Node / any bundler) |@moontra/moonui/tokens.css|
postcss-importdoes not read a package'sexportsmap, so in that pipeline it needs the physical path (it ships in the tarball via the packagefilesfield). Vite and Node are the mirror image: they areexports-aware and reject the physical path. Both routes load the same file — pick one, not both.// app/layout.tsx — the JavaScript route import "@moontra/moonui/tokens.css";
Recommended: also add the semantic layer (shadow-xs, animate-fade-in, duration-fast,
ease-bounce and the elevation/duration/easing tokens). Components render correctly
without it — every variable the preset reads already lives in tokens.css.
@import "@moontra/moonui/src/styles/design-system.css";3. Keep tailwindcss-animate in plugins
Pro's overlays (Dialog, Popover, Select, Toast, NavigationMenu, …) rely on
animate-in, fade-in, slide-in-from-* and data-[state=open]: variants. They come
from the tailwindcss-animate plugin, which the preset deliberately does not bundle
so that the package cannot force a dependency on you. Without it those 25 classes are
simply absent and the overlays pop in without transition.
Bringing your own theme
You are not obliged to use MoonUI's values — the preset reads variables, it does not hardcode colours. Override any of them after the import and Pro follows:
@import "@moontra/moonui/src/styles/tokens.css";
:root {
--primary: 262 83% 58%;
}What you cannot do is define nothing. If you skip tokens.css you must supply all 51
variables yourself, including MoonUI-specific families such as --secondary-500,
--warning-700, --info-subtle and --brand-*.
🔐 License setup
Pro access is resolved at build time, not per request. The flow is:
MOONUI_LICENSE_KEY ──► postinstall.cjs ──► .moonui-license-token ──► withMoonUIProToken
(build env) (validates) (base64 JSON) (inlines into bundle)
│
MoonUIAuthProvider ◄─────────┘
(reads it at runtime)All three steps are required. Skip any one and every Pro component renders ProLockScreen.
1. Provide your license key at build time
# CI / Docker / any build environment
MOONUI_LICENSE_KEY=moonui_xxxxxxxxxxxxMOONUI_LICENSE_KEY is the canonical name. NEXT_PUBLIC_MOONUI_LICENSE_KEY, VITE_MOONUI_LICENSE_KEY and REACT_APP_MOONUI_LICENSE_KEY are also accepted as fallbacks.
2. Generate the token before the build
Package managers skip lifecycle scripts in many CI setups, so run the token generator explicitly:
{
"scripts": {
"prebuild": "node node_modules/@moontra/moonui-pro/scripts/postinstall.cjs",
"build": "next build"
}
}3. Inline the token and mount the provider
Next.js — wrap your config:
// next.config.mjs
import { withMoonUIProToken } from '@moontra/moonui-pro/next-config';
export default withMoonUIProToken({
// ...your Next.js config
});Vite — add the plugin:
// vite.config.js
import moonUIProPlugin from '@moontra/moonui-pro/vite';
export default {
plugins: [moonUIProPlugin()],
};Then wrap your app once, at the root:
// app/layout.tsx
import { MoonUIAuthProvider } from '@moontra/moonui-pro';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<MoonUIAuthProvider>{children}</MoonUIAuthProvider>
</body>
</html>
);
}MoonUIAuthProvider takes no licenseKey prop — it reads the token that step 2 and 3 produced.
⚠️ Without the provider,
hasProAccessis alwaysfalse.useMoonUIAuth()does not throw when no provider is mounted; it silently returns a free-plan state. That is the single most common cause of "my license is valid but everything is locked".
Deploying
The token is written the same way on every platform — Vercel, Netlify, Docker, Kubernetes, Dokploy, or a bare server. Just make sure MOONUI_LICENSE_KEY is present during the build, not only at runtime.
ARG MOONUI_LICENSE_KEY
ENV MOONUI_LICENSE_KEY=$MOONUI_LICENSE_KEY
RUN npm run buildSelf-hosted gotcha: if you build with
NODE_ENV=production, npm skipsdevDependencies. Keepautoprefixer,tailwindcssandpostcssindependencies, or the build fails before the token ever matters.
Full deployment matrix: moonui.dev/docs/authentication
🧩 Usage
import { MoonUIAuthProvider, DataTable, RichTextEditor, Card } from '@moontra/moonui-pro';
function App() {
const data = [
{ id: 1, name: 'John', email: '[email protected]' },
{ id: 2, name: 'Jane', email: '[email protected]' },
];
const columns = [
{ accessorKey: 'name', header: 'Name' },
{ accessorKey: 'email', header: 'Email' },
];
return (
<MoonUIAuthProvider>
<Card className="p-6">
<h1 className="text-2xl font-bold mb-4">MoonUI Pro Demo</h1>
<DataTable data={data} columns={columns} searchable pagination />
<RichTextEditor placeholder="Start writing..." className="mt-4" />
</Card>
</MoonUIAuthProvider>
);
}📊 DataTable
DataTable is built on TanStack Table v8. Column definitions are standard ColumnDef objects.
<DataTable
data={data}
columns={columns}
searchable
filterable
selectable
pagination
pageSize={25}
exportable={{ formats: ['csv', 'json'], filename: 'users' }}
onRowSelect={(rows) => console.log(rows)}
/>Feature flags
features groups the table's optional capabilities:
<DataTable
data={data}
columns={columns}
features={{
sorting: true,
filtering: true,
pagination: true,
search: true,
columnVisibility: true,
rowSelection: true,
density: true,
export: ['csv', 'json'],
}}
/>Quick filters
Dropdown filters, optionally auto-detecting their options from the data:
<DataTable
data={data}
columns={columns}
quickFilters={[
{ column: 'status', label: 'Status', options: 'auto', showCounts: true },
{ column: 'department', label: 'Department', multi: true },
]}
/>Faceted filters
Checkbox filters with counts:
<DataTable data={data} columns={columns} facetedFilters={['category', 'tags']} />Filtering custom-rendered cells
When a cell renders a component, tell the filter where the raw value lives:
const columns = [
{
accessorKey: 'status',
header: 'Status',
cell: ({ row }) => <Badge>{row.getValue('status')}</Badge>,
meta: {
filterType: 'select',
filterOptions: ['Active', 'Pending', 'Completed'],
filterValueAccessor: (row) => row.status,
},
},
];Expandable rows
<DataTable
data={data}
columns={columns}
enableExpandable
renderSubComponent={({ row }) => <pre>{JSON.stringify(row.original, null, 2)}</pre>}
/>🎨 What the bundle does and does not ship
Setup lives in Styling setup; this section is about why it is needed.
Injected by the JavaScript bundle. The ESM build inlines the eight stylesheets its
components import — nprogress, meteors, aurora-background, slash-commands,
table-styles, timeline, plus react-grid-layout and react-resizable from their own
packages — and appends them to <head> on import. Nothing to do on your side.
Not injected, and this is the part people miss. Those eight files are component CSS. They are not the design system:
- Utility classes are not shipped. Every Pro component styles itself with Tailwind
classes (
bg-primary,border-border,text-muted-foreground). Those rules are generated by your Tailwind build, which is why yourcontentglobs must includenode_modules/@moontra/moonui-pro/dist/**. - Token values are not shipped.
dist/index.mjsreads 14 theme variables directly in inline styles, and the utility rules Tailwind generates from its class names pull in the rest — 51 in total. The bundle defines zero of them. They come from@moontra/moonui'stokens.css(or from your own equivalent).
There is no @moontra/moonui-pro/styles.css entry point — importing one fails, and there
is no published Pro stylesheet that would define tokens for the npm route.
The CDN build is the one exception to both rules: it does not inject, and it ships a
companion dist/cdn/index.css that does define the tokens — a CDN page has no
Tailwind build and no way to pull @moontra/moonui's tokens.css, so that one file has
to be enough on its own. See CDN / no-build usage.
MoonUI Pro follows the base MoonUI theming system: HSL triplets in CSS variables and a
.dark class for dark mode — the same system @moontra/moonui uses, from the same file.
🌐 CDN / no-build usage
MoonUI Pro runs from a plain HTML page, with no bundler and no npm install.
React must come from the page, never from the MoonUI Pro bundle. Until 4.20.0 the
CDN build bundled React; a CDN page has to load its own React too, so the page ended up
with two copies, the hook dispatcher was null, and every component using a hook threw
Cannot read properties of null. That was the substance of issue #410. The current build
externalizes React — measured as a controlled experiment on the base package: React inside
the bundle crashed 7 of 7 component scenarios, React outside passed 7 of 7.
Route A — esm.sh (zero setup, works today)
Works against the published package, no build required:
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/[email protected]",
"react/": "https://esm.sh/[email protected]/",
"react-dom": "https://esm.sh/[email protected]",
"react-dom/": "https://esm.sh/[email protected]/",
"next-themes": "https://esm.sh/[email protected]?external=react,react-dom&target=es2022",
"@moontra/moonui-pro": "https://esm.sh/@moontra/[email protected]?bundle&external=react,react-dom&target=es2022"
}
}
</script>All three query parameters are mandatory, and for Pro one of them is fatal rather than merely wasteful:
| Parameter | Drop it and… |
|---|---|
| external=react,react-dom | esm.sh resolves the peer range itself and loads a React independent of your importmap. Every hook-using component crashes. |
| bundle | Pro does not load at all. Pro's module graph contains a CSS side-effect import (react-grid-layout/css/styles.css); in per-module mode esm.sh leaves it as a CSS URL and the browser refuses it — "Expected a JavaScript-or-Wasm module script but the server responded with a MIME type of text/css" — killing the entire graph with no pageerror at all. Measured across four independent runs: the graph never finished in 300 s. |
| target=es2022 | The response carries vary: User-Agent, so the output depends on the browser asking. |
esm.sh is a third party and is not covered by any MoonUI SLA. For a paid product this is a real trade-off: the license gate's code would live inside a bundle built by someone else's pipeline. It is not a secrecy risk — the package is public on npm and the compiled source has always been downloadable — it is a continuity and determinism risk. Route B exists so the artifact that enforces the gate is ours.
Route B — MoonUI Pro's own CDN artifacts
Not published yet. These files are produced by this repository's build but ship with the next release. The URLs below show the shape they will take, not links that resolve today. The
dist/cdn/index.global.jspublished in 4.20.0 and earlier is the old, React-bundled build described above — do not use it.
| File | Format | Global | React support |
|---|---|---|---|
| dist/cdn/index.global.js | IIFE | window.MoonUIPro | React 18 only |
| dist/cdn/index.esm.js | ESM + importmap | — | React 18 and 19 |
| dist/cdn/index.css | stylesheet | — | both |
unpkg and jsdelivr in package.json point at the IIFE build.
Why two formats: the IIFE build reads React off window.React, which requires React's
UMD build — and React 19 publishes no UMD build. On React 19 the ESM file is the only
option. That is where React left the UMD format, not a MoonUI limitation.
<!-- React 18, IIFE -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@moontra/moonui-pro/dist/cdn/index.css">
<script src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@moontra/moonui-pro/dist/cdn/index.global.js"></script>
<script>
const { MoonUIAuthProvider, GradientText } = window.MoonUIPro;
ReactDOM.createRoot(document.getElementById("root")).render(
React.createElement(MoonUIAuthProvider, null,
React.createElement(GradientText, null, "Hello"))
);
</script>One stylesheet is enough. Unlike the npm route, index.css ships the design tokens as
well as the utilities — a CDN page has no Tailwind build to generate them and no way to
reach @moontra/moonui's tokens.css.
Verified in a real browser against the produced artifacts — IIFE + React 18, ESM + React 18,
ESM + React 19: 690 exports, 5 of 5 cases rendered, zero crashes, zero page errors.
Reproduce with npm run verify:cdn inside packages/moonui-pro.
Licensing on a CDN page
The license gate works on the CDN and it is fail-closed. Measured in all three loader
configurations with no license present: across 120 sampled animation frames, the real Pro
content appeared in zero of them; components render ProLockScreen instead.
A license can be granted at runtime, but today there is exactly one way and it is not a product:
// Development only. Not a supported distribution mechanism.
localStorage.setItem("moonui_license_token", JSON.stringify(tokenPayload));With that token present, the same measurement flips: real Pro content in 119 of 120 frames (IIFE + React 18) and 117 of 120 (ESM + React 19).
The intended flow — passing a key via a data-moonui-license script attribute and
validating it against the origin server — is designed but not implemented. Until it
lands, treat CDN usage of Pro as prototyping.
Measurement caveat for anyone re-running this: if the MoonUI CLI auth server is running on
localhost:7878, the provider will ask it and silently grant Pro access to "unlicensed" pages. An earlier measurement was invalidated exactly this way (117 of 120 frames of fake Pro content).scripts/cdn/verify-cdn.mjsaborts that request; an internet CDN consumer has no such server.
Styling limits and browser support
index.css is generated by scanning MoonUI Pro's own source, so it contains the classes
Pro components use and nothing else. Your own utility classes — mt-[37px], text-[13px] —
are not in it. Add Tailwind Play CDN
alongside it (Tailwind marks Play CDN as not for production: browser-side compilation,
FOUC, Tailwind v3, third external dependency), or use inline styles.
<script type="importmap"> requires Chrome/Edge 89+, Safari 16.4+, Firefox 108+ (per
MDN/caniuse; not measured here). Older browsers need a polyfill such as es-module-shims,
which MoonUI has not tested.
⚡ Performance
- Virtualization —
VirtualList,SelectableVirtualListfor large collections - Lazy rendering —
LazyListdefers offscreen work - Tree shaking — ESM-only build; import only what you use
import { VirtualList } from '@moontra/moonui-pro';
<VirtualList
items={thousandsOfItems}
itemHeight={50}
renderItem={({ item, index }) => <div key={item.id}>Row {index}: {item.name}</div>}
/>📱 Mobile & Touch
import { SwipeableCard, GestureDrawer } from '@moontra/moonui-pro';
<SwipeableCard onSwipeLeft={handleSwipeLeft} onSwipeRight={handleSwipeRight}>
<CardContent />
</SwipeableCard>📦 Package Details
- Format: ESM only (
dist/index.mjs, 2.53 MiB unminified in 4.19.2), component styles injected by JS - CDN: two minified bundles —
dist/cdn/index.global.js(IIFE, 2.98 MiB, global nameMoonUIPro) anddist/cdn/index.esm.js(ESM, 2.96 MiB) — plusdist/cdn/index.css(208 KB, 31 KB gzipped: component styles, utilities and design tokens). React is not bundled in either; see CDN / no-build usage - Types: full TypeScript definitions included
- Peer dependencies (declared): React 18+ or 19, React DOM,
next-themes - Also required, not declared as peers: Tailwind CSS v3 and
tailwindcss-animateat build time, and@moontra/moonuifor the preset and design tokens — see Styling setup - Built on: TanStack Table v8, Recharts, Framer Motion
The CDN bundle has no build step, so it cannot receive a build-time license token. Without one, Pro components render their lock screen — verified fail-closed, with the real Pro content never appearing in any of 120 sampled frames. A license can be supplied at runtime, but only by writing
moonui_license_tokenintolocalStorageby hand; that is not a productized flow. See CDN / no-build usage.
🔒 License & Privacy
- A valid license key is required for production builds; development works without one
- The license key is validated once at build time against
moonui.dev - No telemetry. The package does not phone home at runtime and does not transmit your domain
- The published bundle is plain, readable ESM — it is licensed, not obfuscated
💳 Pricing
MoonUI Pro is a one-time purchase. There is no subscription.
| Plan | Price | Includes | |------|-------|----------| | Professional | $79 one-time | 1 device, 100+ Pro components, lifetime updates | | Team | $199 one-time | 3 developer licenses | | Enterprise | $499 one-time | Unlimited devices, white-label |
🛠️ Development
git clone https://github.com/oguzhanayyldz/moonui
cd moonui/packages/moonui-pro
npm install
npm run dev # watch build
npm run build # production build
npm run test # jest
npm run lint # eslint🔗 Ecosystem
- @moontra/moonui — Base component library (MIT). Required by Pro for the Tailwind preset and design tokens; its components are optional
- @moontra/moonui-cli — Command line tools
- @moontra/moonui-mcp-server — AI / MCP integration
📚 Documentation & Support
- Website: moonui.dev
- Docs: moonui.dev/docs
- License & deployment: moonui.dev/docs/authentication
- Issues: github.com/oguzhanayyldz/moonui/issues
- Email: [email protected]
📄 License
Licensed under a Commercial License. See LICENSE for details.
- Valid license key required for production use
- Development usage allowed without a license
- License includes updates and support
- Licensed per device/developer — see the pricing table above
Website • Documentation • Pricing
Built with ❤️ for developers who demand excellence
