npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cabraule/chameleon-ui

v0.2.1

Published

Automatic UI adaptation SDK for React

Readme

🦎 Chameleon UI

Automatic UI adaptation for React — Respects your users' preferences without a single line of theme code.

npm version license React PRs Welcome


✨ 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-ui

Quick 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 | false

useAccessibility()

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 dev

Open an issue before submitting a pull request for major changes.


License

MIT © Cabraule