@cabraule/chameleon-ui
v0.2.1
Published
Automatic UI adaptation SDK for React
Maintainers
Readme
🦎 Chameleon UI
Automatic UI adaptation for React — Respects your users' preferences without a single line of theme code.
✨ One component. Zero config. Perfect adaptation.
<ChameleonProvider licenseKey="cha-free-demo">
<App />
</ChameleonProvider>That's it. Your app now adapts to:
- 🌙 Dark / light mode based on system preference and time of day
- 👁️ High contrast mode
- 🎨 Color blindness friendly palette
- ⚡ Reduced motion
- 🌍 User language detection
The problem
Every time you build an app, your designer creates multiple mockups — light theme, dark theme, high contrast variants. Your developer hardcodes every condition. And your user still gets a generic interface that doesn't match their real context.
That's a lot of work for a bad result.
The solution
Chameleon detects your app's existing theme, reads your styles, and automatically generates the right adaptation — without breaking what you already built.
Same app. Different users. Right interface every time.
Install
npm install @cabraule/chameleon-uiQuick start
import { ChameleonProvider } from '@cabraule/chameleon-ui'
export default function App() {
return (
<ChameleonProvider licenseKey="cha-free-demo">
<YourApp />
</ChameleonProvider>
)
}Without a license key, Chameleon works using native browser detection only — no AI analysis:
<ChameleonProvider>
<App />
</ChameleonProvider>How adaptation works
Chameleon follows this logic automatically:
| App theme | Time of day | System preference | Action | |---|---|---|---| | Light | Day | None | ✅ Nothing — stay light | | Light | Night | None | 🌙 Switch to dark | | Dark | Day | None | ☀️ Switch to light | | Dark | Night | None | ✅ Nothing — stay dark | | Any | Any | Dark (manual) | 🌙 Always dark | | Any | Any | Light (manual) | ☀️ Always light |
System preference always wins. Time-based logic only applies when the user hasn't manually set a preference on their device.
Setup by Framework
🎨 With Tailwind CSS
1. Configure Tailwind dark mode
// tailwind.config.js
module.exports = {
darkMode: 'class', // Required
content: [
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}',
],
}2. Use Chameleon variables as fallbacks (optional)
/* globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--background: var(--chameleon-bg, #ffffff);
--foreground: var(--chameleon-text-primary, #171717);
--card: var(--chameleon-card-bg, #ffffff);
--border: var(--chameleon-border, #e5e5e5);
}
body {
background: var(--background);
color: var(--foreground);
}3. Wrap your app
import { ChameleonProvider } from '@cabraule/chameleon-ui'
export default function App() {
return (
<ChameleonProvider licenseKey="cha-free-demo">
<YourApp />
</ChameleonProvider>
)
}Chameleon automatically toggles the .dark class on <html> — all your dark: Tailwind classes work instantly.
🎨 With CSS Variables
/* styles.css */
:root {
--background: #ffffff;
--foreground: #171717;
--primary: #2563eb;
--card: #f5f5f5;
--border: #e5e5e5;
}
body {
background: var(--chameleon-bg, var(--background));
color: var(--chameleon-text-primary, var(--foreground));
}
.card {
background: var(--chameleon-card-bg, var(--card));
border: 1px solid var(--chameleon-border, var(--border));
}
button {
background: var(--chameleon-primary, var(--primary));
color: var(--chameleon-primary-text, #ffffff);
}Chameleon reads your existing variables and generates adapted versions automatically.
🎨 With plain CSS / SCSS
Chameleon reads the computed styles of your DOM elements and injects style overrides. For best results, define your colors as CSS variables on :root.
// styles.scss
:root {
--color-bg: #ffffff;
--color-text: #171717;
--color-primary: #2563eb;
}
body {
background: var(--chameleon-bg, var(--color-bg));
color: var(--chameleon-text-primary, var(--color-text));
}⚠️ Note: Apps using only hardcoded CSS colors (no CSS variables) will get partial adaptation. For full accuracy, migrate your key colors to CSS variables.
Read the state anywhere
import { useChameleon } from '@cabraule/chameleon-ui'
function MyComponent() {
const {
theme,
highContrast,
colorBlindMode,
language,
prefersReducedMotion,
adaptation, // 'none' | 'darken' | 'lighten'
appBrightness, // original theme of your app
} = useChameleon()
return (
<div>
<p>Theme: {theme}</p>
<p>Adaptation: {adaptation}</p>
<p>Language: {language}</p>
</div>
)
}Hooks
useTheme()
import { useTheme } from '@cabraule/chameleon-ui'
const { theme, prefersReducedMotion } = useTheme()
// theme → 'light' | 'dark'
// prefersReducedMotion → true | falseuseAccessibility()
import { useAccessibility } from '@cabraule/chameleon-ui'
const { highContrast, forcedColors, colorBlindMode } = useAccessibility()
// highContrast → 'normal' | 'high'
// forcedColors → true | false
// colorBlindMode → null | 'deuteranopia' | 'protanopia' | 'tritanopia'CSS Variables Reference
| Variable | Description |
|---|---|
| --chameleon-bg | Main background |
| --chameleon-card-bg | Card / surface background |
| --chameleon-text-primary | Primary text |
| --chameleon-text-secondary | Secondary / muted text |
| --chameleon-primary | Brand / accent color |
| --chameleon-primary-text | Text on primary color |
| --chameleon-border | Border color |
| --chameleon-surface | Alternative surface |
| --chameleon-font-scale | Font boost in high contrast (0px default, 2px HC) |
| --chameleon-motion | Motion multiplier (1 default, 0 reduced motion) |
Best Practices for Developers
Follow these guidelines to get the best theme adaptation from Chameleon.
Use CSS variables for your key colors
/* Best — Chameleon reads and adapts these automatically */
:root {
--background: #ffffff;
--foreground: #171717;
--primary: #6366f1;
--card: #f5f5f5;
}
body { background: var(--background); color: var(--foreground); }Use Tailwind semantic classes instead of arbitrary values
{/* Good — Chameleon adapts standard Tailwind classes */}
<div className="bg-white text-gray-900 border-gray-200">
{/* Works but harder to adapt — arbitrary hex values */}
<div className="bg-[#f5f5f5] text-[#1c1c1e] border-[#dadce0]">Give explicit backgrounds to containers
{/* Good — Chameleon knows this div has a white background */}
<div className="bg-white rounded-lg p-6">
<p className="text-gray-700">Content</p>
</div>
{/* Bad — div inherits background, Chameleon can't distinguish it */}
<div className="rounded-lg p-6">
<p className="text-gray-700">Content</p>
</div>Avoid !important on colors
/* Bad — blocks Chameleon */
.my-card { background-color: #fff !important; }
/* Good — Chameleon can override it */
.my-card { background-color: #fff; }Prefer CSS classes over inline styles for colors
{/* Bad — inline styles are harder to override */}
<div style={{ background: '#ffffff', color: '#000000' }}>
{/* Good — classes are easy to override */}
<div className="bg-white text-gray-900">Use data-chameleon-skip for content areas
{/* PDF viewers, canvas, code editors — don't adapt these */}
<div data-chameleon-skip>
<PDFViewer document={doc} />
</div>
{/* Canvas and video are automatically excluded */}
<canvas /> {/* Never touched by Chameleon */}Keep gradients on the element, not a parent wrapper
{/* Good — Chameleon detects and adapts the gradient */}
<section className="bg-linear-to-br from-indigo-50 via-white to-blue-50">
{/* Bad — gradient on a wrapper div without explicit class */}
<div style={{ background: 'linear-gradient(...)' }}>For Ant Design / MUI / Chakra — let the framework handle structure
Chameleon automatically detects and adapts Ant Design, MUI, and Chakra UI components. No special config needed. Just wrap your app:
<ChameleonProvider licenseKey="cha-free-demo">
<ConfigProvider> {/* antd */}
<App />
</ConfigProvider>
</ChameleonProvider>Troubleshooting
Dark mode not activating on Tailwind
Make sure you have darkMode: 'class' in tailwind.config.js — this is required.
Colors not adapting at all
1. ChameleonProvider not at root level
// ❌ Wrong
function Page() {
return <ChameleonProvider><Content /></ChameleonProvider>
}
// ✅ Correct — wrap at the very top
function App() {
return <ChameleonProvider><Page /></ChameleonProvider>
}2. Colors hardcoded with !important
/* ❌ Blocks Chameleon */
.my-class { color: #000 !important; }
/* ✅ Use CSS variables */
.my-class { color: var(--chameleon-text-primary); }3. Inline styles
{/* ❌ Can't be overridden */}
<div style={{ color: '#000' }}>Text</div>
{/* ✅ Use CSS classes */}
<div className="text-foreground">Text</div>Next.js App Router setup
ChameleonProvider uses React hooks — it must be in a Client Component:
// app/providers.tsx
'use client';
import { ChameleonProvider } from '@cabraule/chameleon-ui';
export function Providers({ children }: { children: React.ReactNode }) {
return (
<ChameleonProvider licenseKey="cha-free-demo">
{children}
</ChameleonProvider>
);
}// app/layout.tsx
import { Providers } from './providers';
export default function RootLayout({ children }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}For Vite / CRA, add this in index.html before React loads:
<script>
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.classList.add('dark');
}
</script>Text unreadable after adaptation
Chameleon includes an automatic contrast fixer that checks every text element against its real background. If issues persist:
- Make sure elements have explicit backgrounds (not transparent)
- Update to the latest version:
npm update @cabraule/chameleon-ui
Framework support
| Framework | Status | |---|---| | React 18+ | ✅ Supported | | Next.js 13+ App Router | ✅ Supported | | Next.js 12 Pages Router | ✅ Supported | | Vite + React | ✅ Supported | | Tailwind CSS v3 / v4 | ✅ Supported | | shadcn/ui | ✅ Supported | | Ant Design v5+ | ✅ Supported | | Material UI (MUI) v5+ | ✅ Supported | | Chakra UI v3 | ✅ Supported | | CSS / CSS Variables | ✅ Supported | | SCSS / SASS | ✅ Supported (best with CSS variables) | | Plain CSS | ✅ Supported | | Vue.js | 🔜 Coming in V2 | | React Native | 🔜 Coming in V2 |
Browser support
| Browser | Minimum version | |---|---| | Chrome | 76+ | | Edge | 79+ | | Firefox | 67+ | | Safari | 12.1+ |
Roadmap
✅ MVP (current)
- [x] Automatic light / dark theme detection
- [x] Time-based adaptation (day / night)
- [x] System preference — always takes priority
- [x] High contrast mode
- [x] Color blindness mode
- [x] Reduced motion support
- [x] Language detection
- [x] Tailwind CSS v3 / v4 support
- [x] shadcn/ui support
- [x] Ant Design support
- [x] Material UI (MUI) support
- [x] Chakra UI v3 support
- [x] CSS / CSS Variables / SCSS support
- [x] AI-powered theme generation (Claude Sonnet)
- [x] Automatic WCAG contrast fixes
- [x] Gradient adaptation (from-, via-, to-*)
- [x] Inline style adaptation
- [x] Portal / modal / dropdown detection
- [x] Canvas / PDF / video exclusion
- [x] Supabase persistent cache
🔜 V1
- [ ] Font size scaling
- [ ] Color palette editor (Pro)
- [ ] Theme preview panel
🔜 V2
- [ ] Vue.js support
- [ ] React Native support
- [ ] Analytics dashboard (Pro)
Contributing
git clone https://github.com/cabraule/chameleon-ui
cd chameleon-ui
npm install
npm run devOpen an issue before submitting a pull request for major changes.
License
MIT © Cabraule
