Skip to navigation

Style components

Experiences SDK is currently available in alpha. APIs are unstable and subject to change.

Design properties authored in Contentful, such as spacing, color, and typography, reach your components as ordinary props. The SDK resolves them while it resolves the experience, so your components style themselves from props, with no SDK code.

Style from props

Each design property arrives as a prop with the same name: a design property named backgroundColor arrives as backgroundColor, with design tokens already resolved. Declare the design properties a component uses, read them by name, and style from them:

// components/Heading.tsx
import type { CSSProperties } from 'react';
interface HeadingProps {
text?: string;
// Design properties:
as?: 'h1' | 'h2' | 'h3';
fontSize?: string;
fontWeight?: string;
}
export function Heading({ text, as = 'h2', fontSize, fontWeight }: HeadingProps) {
const Tag = as;
const style: CSSProperties = { fontSize, fontWeight };
return <Tag style={style}>{text}</Tag>;
}

Don’t collect undeclared props with ...rest and spread them onto an HTML element. Design property names aren’t HTML attributes, so React warns and they end up in the markup.

Design properties come in two kinds, and both arrive the same way:

  • CSS values, such as fontSize or backgroundColor: pass them straight into a style.
  • Semantic values, such as variant, as, or ratio: read them by name and map them to markup or CSS. A design property name doesn’t have to match a CSS property.

The SDK doesn’t select responsive values at runtime. Use CSS media queries for responsive styling.

Resolve design tokens

A design property can hold a design token instead of a value. The token arrives as { type: 'DesignToken', value: '<token-id>' }. Only your design system knows what a token ID means, so add a resolveToken function to your configuration that returns the value for an ID:

import type { Config, ResolveToken } from '@contentful/experiences-react';
const resolveToken: ResolveToken = (token) => designTokens[token.value];
export const experienceConfig: Config = { components, resolveToken };

The token ID format is yours: dotted, slashed, or whatever your token export uses. The SDK passes you token.value and uses whatever you return. Some common sources:

// CSS custom properties: no JavaScript cost, and the browser handles theme changes.
resolveToken: (token) => `var(--${token.value.replaceAll('.', '-')})`;
// A tokens object or design tokens package.
resolveToken: (token) => designTokens[token.value];
// A resolved Tailwind theme, walked by ID path.
resolveToken: (token) => token.value.split('.').reduce((o, k) => o?.[k], theme);

When resolveToken returns undefined, or isn’t configured, the raw token reaches the component and the SDK reports a diagnostic.

Use Tailwind, CSS-in-JS, or class names

The SDK doesn’t generate a stylesheet or class names. Class-based and CSS-in-JS systems work with the values resolveToken returns: return a var(--...) reference, a theme value, or a class name, and use the prop in a style object, a styled component, or a clsx call.

Read design values without props

A child that isn’t a registered component gets no props from the SDK. To style it from the design values of the nearest registered component, read them from context. Use this only for nested children, or for design values needed outside rendering, such as in an effect. Registered components should read props.

'use client';
import { useDesignValues } from '@contentful/experiences-react';
// Not registered, so it has no design props of its own.
function Badge({ label }: { label: string }) {
const design = useDesignValues<{ color?: string }>();
return <span style={{ color: design.color }}>{label}</span>;
}

useDesignValues() is a client hook, so the component must be a client component. It returns {} outside a renderer. The type argument is an assertion, not a runtime check, so treat each key as possibly undefined.

To turn a design record into a style object, use toCss(design, { include, exclude }). It keeps the keys that map to CSS properties and drops semantic ones.