@morphuiapp/morphui
v0.4.1
Published
Intelligent UI SDK for React
Maintainers
Readme
morph
Intelligent UI SDK for React
Your app has one interface. Your users are not one person.
Website · Documentation · Dashboard · Pricing
What is Morph?
Morph is an intelligent UI SDK that makes your React app personal for every user — automatically.
No theme files to write. No dark mode to build. No accessibility backlog. One line of code. That's it.
<MorphProvider licenseKey="morph-free-demo">
<App />
</MorphProvider>Works without a license key — native detection is always free. Add a key for AI-powered adaptation. Get your key →
Three layers of intelligence
V1 — Context Intelligence
Morph reads the room the moment your app loads.
- 🌙 Dark at night. Light in the morning.
- ♿ High contrast when the system asks.
- 🎨 Color-blind safe palette when needed.
- ⚡ Reduced motion. Bold text. Language. All detected.
System preference always wins. Time-based logic is a smart fallback — never an override.
V1 — Design Intelligence
Claude reads your actual design — not just your colors.
Not a color inverter. Morph reads your Tailwind classes, computed styles, inline styles, Ant Design tokens — and reasons about your design like a senior designer would. What's a background? What's a card? What's a brand color that should never change?
The result: 4 surface depth levels generated from your palette, WCAG AA verified on every element, gradients adapted, portals and modals covered. It looks hand-crafted. Because the reasoning behind it was.
V2 — Behavioral Intelligence (Pro)
Your interface learns this person — and 11 papercuts disappear.
Morph V2 fixes the small frustrations every web app has: the white flash between routes, the form that resets on back-button, the scroll position that vanishes after a refresh, the dialog that doesn't trap focus, the autofill that breaks your validation, the rage-tap on a 24px button. All local, all private, all in IndexedDB. Nothing leaves the browser.
- 6 auto-engines that just work — opt-out per feature
- 5 drop-in components for the parts where a component is the right answer
- 3 hooks for storage, cross-tab sync, and autofill
Always with their permission. Always reversible. Each engine is a lazy chunk — zero overhead if unused.
Install
npm install @morphuiapp/morphuiQuick start
import { MorphProvider } from '@morphuiapp/morphui'
export default function App() {
return (
<MorphProvider licenseKey="morph-free-demo">
<YourApp />
</MorphProvider>
)
}How adaptation works
| App theme | Time of day | System preference | Action | |-----------|-------------|-------------------|--------| | Light | Day | None | ✅ Stay light | | Light | Night | None | 🌙 Switch to dark | | Dark | Day | None | ☀️ Switch to light | | Dark | Night | None | ✅ Stay dark | | Any | Any | Dark (manual) | 🌙 Always dark | | Any | Any | Light (manual) | ☀️ Always light |
Read the state anywhere
import { useMorph } from '@morphuiapp/morphui'
function MyComponent() {
const {
theme, // 'dark' | 'light'
adaptation, // 'darken' | 'lighten' | 'none'
highContrast, // 'normal' | 'high'
colorBlindMode, // null | 'deuteranopia' | 'protanopia' | 'tritanopia'
prefersReducedMotion, // true | false
language, // 'en' | 'fr' | ...
appBrightness, // original theme of your app
// V2 — Pro
morphingMode, // 'digest' | 'article' | 'gallery'
zoneOrder, // { search: 1, feed: 2 }
} = useMorph()
}Hooks
useTheme()
import { useTheme } from '@morphuiapp/morphui'
const { theme, prefersReducedMotion } = useTheme()
// theme → 'light' | 'dark'useAccessibility()
import { useAccessibility } from '@morphuiapp/morphui'
const { highContrast, forcedColors, colorBlindMode } = useAccessibility()You always stay in control
data-morph-skip — protect a subtree
Put this on any element and Morph stops at that boundary — styles, ordering, and tracking. All untouched.
<div data-morph-skip>
{/* Morph never touches this */}
<BrandLogo />
<PDFViewer />
</div>data-morph-force — re-enable inside a skipped zone
<div data-morph-skip>
<LegacyWidget />
<section data-morph-force>
{/* Morph applies again here */}
<ModernCard />
</section>
</div>safeMode — detect without touching anything
<MorphProvider safeMode>
<App />
</MorphProvider>Morph detects everything, applies nothing. useMorph() still returns all values with safeMode: true.
Setup by framework
Tailwind CSS
// tailwind.config.js
module.exports = {
darkMode: 'class', // Required
content: ['./src/**/*.{js,ts,jsx,tsx}'],
}Morph automatically toggles .dark on <html> — all your dark: classes work instantly.
CSS Variables
body {
background: var(--morph-bg, var(--background));
color: var(--morph-text-primary, var(--foreground));
}
.card {
background: var(--morph-card-bg, var(--card));
border: 1px solid var(--morph-border, var(--border));
}Next.js App Router
// app/providers.tsx
'use client'
import { MorphProvider } from '@morphuiapp/morphui'
export function Providers({ children }: { children: React.ReactNode }) {
return (
<MorphProvider licenseKey="morph-free-demo">
{children}
</MorphProvider>
)
}// app/layout.tsx
import { Providers } from './providers'
export default function RootLayout({ children }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}Ant Design / MUI / Chakra
No special config needed. Wrap your app — Morph handles the rest.
<MorphProvider licenseKey="morph-free-demo">
<ConfigProvider> {/* antd */}
<App />
</ConfigProvider>
</MorphProvider>V2 — Things that just work
Six auto-engines run inside MorphProvider. No code to write. Each one ships as its own lazy chunk and is opt-out via a single prop.
PreNavSkeleton — kill the white flash
The frustration: every router transition repaints the page white before the new route renders. Users think the app froze.
The fix: Morph snapshots the layout structure of every page you visit, intercepts navigation, and paints a same-shape skeleton in the gap between unmount and mount. The skeleton matches your actual surface colors (it reads --morph-bg / --morph-card-bg).
Auto-on. Disable with <MorphProvider preNav={false}>.
WhiteIslandFixer — no more white blocks in dark mode
Third-party iframes (Stripe, Calendly, YouTube) and PNG logos with white backgrounds scream in dark mode. Morph detects them, dims iframes via the cover trick, and applies mix-blend-mode: multiply to white-pixel logos.
Auto-on. Disable with <MorphProvider whiteIslandFix={false}>.
ScrollRestoration — every page remembers
Browsers restore scroll on back-navigation, sometimes. Refreshes wipe it. Anchored elements (sticky headers) shift on restore. Morph snapshots scroll position per route, restores after first paint, and adjusts for layout shift.
Auto-on. Disable with <MorphProvider scrollRestore={false}>.
ImproperTapDetector — catches double-taps that mean rage
Users double-tap a button when they think nothing happened. Morph detects the pattern (same target, <300ms apart, no visible change) and shows a non-blocking "Action confirmed" undo banner so the second tap doesn't fire a duplicate.
Auto-on. Disable with <MorphProvider improperTap={false}>.
LostTapDetector — flags missed touch targets
When a user taps near but not on a button, that's friction worth knowing about. Morph reports near-miss taps to the dashboard so you see which targets are too small. Nothing visible to the end-user.
Auto-on. Disable with <MorphProvider lostTap={false}>.
V2 — Drop-in components
Five components for cases where a component is the cleaner answer than an engine.
MorphForm — no more lost form data
The frustration: user fills a 12-field form, hits the back button, comes back. Empty.
Wrap any form. Morph snapshots field values to IndexedDB on every change, restores on mount, clears on submit.
import { MorphForm } from '@morphuiapp/morphui'
<MorphForm id="contact-form" onSubmit={handleSubmit}>
<input name="email" />
<textarea name="message" />
<button type="submit">Send</button>
</MorphForm>MorphLoader — adaptive loading state
A loader that respects prefers-reduced-motion, matches your theme, and uses a real skeleton (not a spinner) when given a shape prop.
import { MorphLoader } from '@morphuiapp/morphui'
<MorphLoader shape="card" count={3} />MorphDialog — accessible modal that traps focus
Replaces the homemade <div className="modal">. Backdrop click to close, ESC to close, focus trap, restores focus to the trigger on close, applies inert to the rest of the page so screen readers ignore it.
import { MorphDialog } from '@morphuiapp/morphui'
<MorphDialog open={open} onClose={() => setOpen(false)} title="Confirm">
Delete this license?
</MorphDialog>MorphPhoneInput — international phone field that adapts
Auto-detects the user's country from navigator.language, formats as they type, validates on blur. Theme-aware, RTL-aware.
import { MorphPhoneInput } from '@morphuiapp/morphui'
<MorphPhoneInput value={phone} onChange={setPhone} />MorphZone — the original V2 primitive
After enough sessions, Morph reorders zones based on what this user actually uses. Always with their permission. Always with an Undo button.
import { MorphZone } from '@morphuiapp/morphui'
<MorphZone id="search" priority={1}>
<SearchSection />
</MorphZone>
<MorphZone id="feed" priority={2}>
<FeedSection />
</MorphZone>V2 — Utility hooks
useStorage() — persistence with automatic fallback
IndexedDB → localStorage → in-memory. Same API everywhere. Returns [value, setValue, { ready }].
import { useStorage } from '@morphuiapp/morphui'
const [draft, setDraft, { ready }] = useStorage('post-draft', '')useTabSync() — keep state in sync across tabs
BroadcastChannel under the hood. When the user has your app in two tabs, both stay coherent.
import { useTabSync } from '@morphuiapp/morphui'
const [count, setCount] = useTabSync('cart-items', 0)useAutoFillGuard() — detect browser autofill
Browser autofill doesn't fire onChange consistently. This hook uses the :-webkit-autofill CSS animation trick to fire a callback the moment a field is autofilled, so your validation runs.
import { useAutoFillGuard } from '@morphuiapp/morphui'
const ref = useAutoFillGuard((field) => trigger(field.name))
return <input ref={ref} name="email" />CSS Variables reference
| Variable | Description |
|----------|-------------|
| --morph-bg | Main background |
| --morph-card-bg | Card / surface background |
| --morph-text-primary | Primary text |
| --morph-text-secondary | Secondary / muted text |
| --morph-primary | Brand / accent color |
| --morph-primary-text | Text on primary color |
| --morph-border | Border color |
| --morph-surface | Alternative surface |
| --morph-font-scale | Font boost in high contrast |
| --morph-motion | Motion multiplier |
Framework support
| Framework | Status | |-----------|--------| | React 18+ | ✅ | | Next.js 13+ App Router | ✅ | | Next.js 12 Pages Router | ✅ | | Vite + React | ✅ | | Tailwind CSS v3 / v4 | ✅ | | shadcn/ui | ✅ | | Ant Design v5+ | ✅ | | Material UI v5+ | ✅ | | Chakra UI v3 | ✅ | | CSS / SCSS | ✅ | | Vue.js | 🔜 V3 |
Troubleshooting
Dark mode not activating on Tailwind
Add darkMode: 'class' in tailwind.config.js.
Colors not adapting
MorphProvidermust wrap your app at root level- Avoid
!importanton color properties - Prefer CSS classes over inline styles
Next.js flash of wrong theme
<script>
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.classList.add('dark')
}
</script>Text unreadable after adaptation
Make sure elements have explicit backgrounds — not transparent.
Update to the latest version: npm update @morphuiapp/morphui
Pricing
| Feature | Free | Professional | Business | Enterprise | | ------- | ---- | ------------ | -------- | ---------- | | Price | $0 | $29/mo | $99/mo | Custom | | API calls/day | 100 | 5,000 | 50,000 | Unlimited | | License keys | 1 | 5 | 25 | Unlimited | | Dark mode + Accessibility | ✅ | ✅ | ✅ | ✅ | | AI theme generation | ✅ | ✅ | ✅ | ✅ | | V2 auto-engines (PreNav, ScrollRestore, …) | — | ✅ | ✅ | ✅ | | V2 components (Form, Dialog, Zone, …) | — | ✅ | ✅ | ✅ | | Analytics dashboard | — | — | ✅ | ✅ | | AI recommendations | — | — | ✅ | ✅ | | SLA + private support | — | — | — | ✅ |
Roadmap
✅ Live now
- Automatic dark / light theme
- WCAG AA — guaranteed, not hoped for
- System preferences — all of them
- AI-powered theme generation (Claude)
- Tailwind, shadcn, Ant Design, MUI, Chakra, CSS / SCSS
✅ V2 — Behavioral Intelligence
- Zone tracking and reordering
- Interface morphing (digest / article / gallery)
- Personal heatmap — cross-session
- Navigation pattern detection
- Analytics dashboard
- AI-powered recommendations (opt-in)
🔜 V3
- Vue.js support
- React Native support
morphui.dev · Docs · Dashboard · npm
Every user deserves an interface made for them.
MIT License
