Skip to main content

For developers: Web

Chameleon is a collection of reusable tools and components that are divided into multiple packages. They can be used together or separately depending on your team's needs.

NPM packages

All of Chameleon for the Web platform is distributed through NPM packages*.

  • We publish to the GitLab NPM registry under the @chameleon scope. Configure your .npmrc to point the scope at the registry:
@chameleon:registry=https://gitlab.mediahuisgroup.com/api/v4/projects/1237/packages/npm/
//gitlab.mediahuisgroup.com/api/v4/projects/1237/packages/npm/:_authToken=${GITLAB_TOKEN}

For access, contact Service Desk

Themes

Every brand has its own Chameleon theme package containing all design tokens and assets for that brand.

$ npm install @chameleon/theme-wl

Design tokens

Design tokens for the web platform are available in multiple formats.

Javascript

To import design tokens in JS, there's 2 options.

  1. You can get the tokens that are returned as CSS Custom Properties.
// this exports as CSS Custom Props
import * as tokensAsCSSCustomProperties from '@chameleon/theme-wl/tokens/js/css-custom-properties';

console.log(tokensAsCSSCustomProperties.colorPrimaryBase); // 'var(--color-primary-base)'

This allows you to offload the resolving of values for subthemes, responsiveness, darkmode, ... to the CSS engine instead of working with raw values.

  1. You can also get the tokens as raw values
// these return raw values
import * as defaultTokens from '@chameleon/theme-wl/tokens';
import * as darkModeTokens from '@chameleon/theme-wl/tokens/dark';
import * as desktopTokens from '@chameleon/theme-wl/tokens/desktop';
import * as sportSubthemeTokens from '@chameleon/theme-wl/tokens/subthemes/sport';

console.log(defaultTokens.colorPrimaryBase); // '#FFFFFF'
console.log(darkModeTokens.colorPrimaryBase); // '#000000'

CSS

When using ChameleonProvider (see below), token CSS is automatically injected. If you need to include it manually:

<link
rel="stylesheet"
href="/node_modules/@chameleon/theme-wl/lib/web/tokens.css"
/>

Other platforms

We also provide these tokens in SCSS and JSON format. See the theme's package.json exports field for more info.

Fonts

We provide a /node_modules/@chameleon/theme-wl/lib/web/fonts.css file that has @font-face declarations set up correctly for you.

Each font comes with a fallback @font-face declaration to minimize CLS. More info found in this article.

When using ChameleonProvider, font CSS is automatically injected. You can also find a brand's font files under /node_modules/@chameleon/theme-wl/lib/web/fonts/.

Icons, logos and illustrations

Icons, logos and illustrations for the web platform are available as SVG files. You can find them under

  • /node_modules/@chameleon/theme-wl/lib/web/icons/
  • /node_modules/@chameleon/theme-wl/lib/web/illustrations/
  • /node_modules/@chameleon/theme-wl/lib/web/logos/

There's also an SVG spritesheet available for icons:

  • /node_modules/@chameleon/theme-wl/lib/web/icons.svg

When using the React component library, icons, logos and illustrations are referenced by name — no imports from theme packages are needed:

import { Icon, Logo, Illustration } from '@chameleon/react';

<Icon name="add" />
<Logo name="logo-main" />
<Illustration name="avatar-placeholder" />

See the Icon, Logo and Illustration component documentation for more details.

React Component Library

For the web platform, we also offer a full fledged component library: @chameleon/react. It integrates neatly with all @chameleon/theme-* packages.

Installation

$ npm install @chameleon/react

Setup

Wrap your application in ChameleonProvider. The provider automatically sets data-chameleon-theme and data-chameleon-color-mode on document.documentElement, loads fonts, and injects design token CSS — no manual HTML attributes or CSS imports needed.

import { ChameleonProvider } from '@chameleon/react';

function App() {
return (
<ChameleonProvider theme="wl">
<MyApp />
</ChameleonProvider>
);
}

Asset serving

By default, assets (icons, logos, illustrations) are served from the Chameleon CDN. If you need to serve assets locally or from a custom location, configure the themeConfig.assets prop:

<ChameleonProvider
theme="wl"
themeConfig={{
assets: {
logos: '/assets/{theme}/logos/',
icons: '/assets/{theme}/',
favicons: '/assets/{theme}/favicons/',
illustrations: '/assets/{theme}/illustrations/',
fonts: '/assets/{theme}/fonts/',
tokens: '/assets/{theme}/tokens/css/',
},
}}
>

The {theme} placeholder is replaced with the actual theme name at runtime.

Icons and the cross-origin <use> restriction

Icons are rendered as references into an SVG sprite sheet:

<svg><use href="https://cdn.example.com/wl/icons.svg#add" /></svg>

Browsers refuse to resolve <use href> when the sprite sheet lives on a different origin than the document — even when the CDN responds with permissive CORS headers. The icon will silently render blank. This means the CDN defaults will not work in production.

To make icons render, configure themeConfig.assets.icons to a URL on your own origin. You have a few options:

1. Proxy the sprite sheet through your app (recommended)

Add a server route that fetches the sprite sheet from the Chameleon CDN and re-serves it from your origin. This is the approach used in the app-with-next example — a Next.js route handler at /api/icons/[theme]/icons.svg proxies the upstream CDN response. Then point the icons asset path at that route:

<ChameleonProvider
theme="wl"
themeConfig={{
assets: {
icons: '/api/icons/{theme}/',
// other assets can stay on the CDN
},
}}
>

2. Self-host the sprite sheets

Copy the per-theme icons.svg file out of the theme package (@chameleon/theme-{brand}/lib/web/icons.svg) into your app's public/static directory at build time, then point the icons asset path at where you serve them:

themeConfig={{
assets: {
icons: '/static/chameleon/{theme}/',
},
}}

Color mode

Pass colorMode to ChameleonProvider to apply a dark or light theme. The provider keeps the data-chameleon-color-mode attribute on the target element in sync at runtime.

<ChameleonProvider theme="wl" colorMode="dark">
<MyApp />
</ChameleonProvider>

Accepted values: 'light' (default) or 'dark'.

SSR

For SSR frameworks (e.g. Next.js App Router), use ChameleonRoot to bake data-chameleon-theme and data-chameleon-color-mode into the HTML at render time, before JavaScript loads. ChameleonProvider then takes over at runtime and keeps the attributes in sync.

// app/layout.jsx
import { ChameleonRoot } from '@chameleon/react';

export default function RootLayout({ children }) {
return (
<ChameleonRoot
lang="en"
defaultTheme="wl"
defaultColorMode="light"
suppressHydrationWarning
>
<body>
<ChameleonProvider theme={theme} colorMode={colorMode}>
{children}
</ChameleonProvider>
</body>
</ChameleonRoot>
);
}
ChameleonRoot and ChameleonProvider
  • ChameleonRoot is a static wrapper that renders any element (default: <html>) with the theme attributes baked in as HTML at render time — no effects, no logic. Its only job is to write the correct values into the SSR markup before JavaScript loads.
  • ChameleonProvider is the runtime layer. It puts theme, colorMode, and themeConfig into context, and keeps the DOM attributes in sync via useLayoutEffect. The target element depends on the props: as writes to a ChameleonRoot it renders itself, rootSelector queries an existing element, and neither defaults to document.documentElement.

Reset

In most cases a CSS reset should already be available within the main website layout.

If that's not the case, simply include the @chameleon/reset CSS to the entry of your app.

import '@chameleon/reset';

Multi-branding

To support multiple brands, install each brand's theme package:

$ npm install @chameleon/theme-gva

Then pass the desired theme to ChameleonProvider:

<ChameleonProvider theme="gva">
<MyApp />
</ChameleonProvider>

The theme can be changed dynamically at runtime — no bundler configuration or rebuild is required.

Hooks

chameleon-react provides hooks for accessing theme configuration in your own components:

import { useThemeConfig, useLocale, useAssets } from '@chameleon/react';

function MyComponent() {
const themeConfig = useThemeConfig(); // theme settings (locale, dateTime, teaser, etc.)
const locale = useLocale(); // locale object with translations
const assets = useAssets(); // resolved asset URLs + helper functions

return (
<img src={assets.getLogoSrc('logo-main')} alt={themeConfig.fullName} />
);
}

You can find an example app in our repo.