Zephora UI

Configuration

Réglages globaux pour chaque composant Zephora — enveloppez votre application une seule fois avec ZephoraConfigProvider et configurez la locale, les couches de z-index des overlays, le conteneur du portail et le défaut headless.

Mise en place

import { ZephoraConfigProvider } from "@zephora/react";

export default function App() {
  return (
    <ZephoraConfigProvider
      locale="tr"
      zIndex={{ modal: 2000, toast: 2100 }}
      appendTo={typeof document !== "undefined" ? document.body : null}
      unstyled={false}
    >
      <YourApp />
    </ZephoraConfigProvider>
  );
}

ZephoraConfigProvider props

PropTypeDéfautDescription
localestring"en"Active locale for component UI strings. Only "en" is embedded; load others from @zephora/theme/locales/* (module or JSON) and register with addLocale().
zIndex{ dropdown?, overlay?, modal?, popover?, toast?, tooltip?: number }Overrides the layering of floating elements. Written as --z-index-* CSS variables on the root element.
appendToHTMLElement | nulldocument.bodyContainer that Portal-based overlays (Dialog, Select menus, Tooltip…) render into.
unstyledbooleanfalseMakes every component headless by default for Tailwind-first apps. A per-component unstyled prop still wins.

Lire la configuration

import { useZephoraConfig, useLocale } from "@zephora/react";

function MyField() {
  const config = useZephoraConfig(); // { locale, zIndex, appendTo, unstyled }
  const { t, messages, locale } = useLocale();
  return <button aria-label={t("close")} />;
}

Couches de z-index

Les composants tirent leur ordre d'empilement de variables CSS avec des valeurs de repli intégrées, si bien que le provider comme le CSS brut peuvent les réajuster :

:root {
  --z-index-dropdown: 1000;
  --z-index-overlay: 1040;
  --z-index-modal: 1050;
  --z-index-popover: 1060;
  --z-index-toast: 1070;
  --z-index-tooltip: 1080;
}

Mode sombre

@zephora/theme fournit des utilitaires de mode sombre automatiques. Le hook useColorScheme résout un schéma (avec mode: "system", il suit la préférence de l'OS en direct) et applique par défaut le thème résolu globalement :

import { useColorScheme } from "@zephora/theme";

function App() {
  // mode: "light" | "dark" | "system" (default "system")
  const { scheme, theme } = useColorScheme({ mode: "system" });
  return <span>Active scheme: {scheme}</span>;
}

useColorScheme(options) props

PropTypeDéfautDescription
mode"light" | "dark" | "system""system""system" follows the OS preference live; "light"/"dark" force a scheme.
light / darkThemelightTheme / darkThemeTheme objects used for each scheme.
applybooleantrueWrite the resolved theme to document.documentElement via applyTheme.
→ returns{ scheme: "light" | "dark"; theme: Theme }The resolved scheme and the theme object in effect.

Les primitives de plus bas niveau sont également exportées :

import { getSystemColorScheme, watchSystemColorScheme } from "@zephora/theme";

// Reads the OS color scheme (SSR-safe; defaults to "light").
const scheme = getSystemColorScheme(); // "light" | "dark"

// Subscribes to OS changes. Returns an unsubscribe function.
const stop = watchSystemColorScheme((next) => console.log(next));
stop();

SSR sans FOUC

Pour le rendu côté serveur, colorSchemeCss(light?, dark?) construit une feuille de style statique qui bascule les thèmes selon la préférence de l'OS — aucun flash du mauvais thème, aucun JavaScript requis avant le paint. Définir data-zephora-scheme sur <html> surcharge la media query (branchez-le sur un bouton utilisateur) :

import { colorSchemeCss } from "@zephora/theme";

// Next.js app router — app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <head>
        <style dangerouslySetInnerHTML={{ __html: colorSchemeCss() }} />
      </head>
      <body>{children}</body>
    </html>
  );
}

classNames de slots

Les composants multi-slots (Dialog, Sheet, Tabs, Card, Popover, Tooltip…) exposent un contrat de classes par slot : la racine accepte classNames typé comme Partial<Record<<Name>Slot, string>> (les unions de noms de slots comme DialogSlot sont exportées). Les classes de slots sont ajoutées après les classes du module et ne sont pas conditionnées par unstyled — elles fonctionnent en mode stylé comme non stylé ; en mode non stylé, elles sont les seules classes. classNames.root se combine avec le prop className existant, qui continue de cibler la racine et est appliqué en dernier. Pour les composants composés, classNames est défini une fois sur la racine et transmis aux parties via le context.

Composants serveur

Le bundle publié @zephora/react est livré avec une directive "use client", vous pouvez donc importer les composants directement dans des arbres de React Server Component (app router de Next.js) sans ajouter vous-même la directive — chaque composant Zephora est un composant client.