Skip to content

Mezzanine-UI/mezzanine

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2,680 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mezzanine UI

A comprehensive React component library with a complete design system, built for modern web applications.

⚠️ Current Status

This project is currently in rc (1.0.0-rc.x) and under active development for v2. While it has been widely utilized across various Rytass internal projects, please note that API changes may still occur before the stable release. We recommend pinning to specific versions in production environments.

{
  "@mezzanine-ui/core": "1.0.0-rc.3",
  "@mezzanine-ui/react": "1.0.0-rc.3",
  "@mezzanine-ui/system": "1.0.0-rc.3",
  "@mezzanine-ui/icons": "1.0.0-rc.3"
}

📚 Documentation

🌐 Browser Support

Browser Minimum Version
Google Chrome 64 (2018)
Edge 79 (2020)
Safari 13.1 (2020)
Firefox 69 (2019)

⚡ Framework Support

Next.js (App Router & Pages Router)

Mezzanine UI fully supports Next.js including the App Router. All React components include the 'use client' directive, making them compatible with React Server Components architecture.

// app/layout.tsx - Works seamlessly with Next.js App Router
import { CalendarConfigProviderDayjs, CalendarLocale } from '@mezzanine-ui/react/dayjs';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <CalendarConfigProviderDayjs locale={CalendarLocale.ZH_TW}>{children}</CalendarConfigProviderDayjs>
      </body>
    </html>
  );
}

All hooks and utilities are also SSR-safe and can be used in Next.js projects without additional configuration.


📦 Installation

Install all required packages:

yarn add @mezzanine-ui/core @mezzanine-ui/react @mezzanine-ui/system @mezzanine-ui/icons

If you plan to use date-related components (DatePicker, Calendar, TimePicker, etc.), install one of the supported date libraries:

# Choose one:
yarn add dayjs      # Recommended - lightweight
yarn add moment     # Legacy support
yarn add luxon      # Alternative

🚀 Quick Start

1. Setup Styles

Create a main.scss file in your project:

@use '~@mezzanine-ui/system' as mzn-system;
@use '~@mezzanine-ui/core' as mzn-core;

// Apply design system variables
:root {
  @include mzn-system.palette-variables(light);
  @include mzn-system.common-variables(default);
}

// Optional: Dark mode support
[data-theme='dark'] {
  @include mzn-system.palette-variables(dark);
}

// Optional: Compact mode support
[data-density='compact'] {
  @include mzn-system.common-variables(compact);
}

// Import component styles
@include mzn-core.styles();

2. Import Styles

Import the stylesheet at your app's entry point:

import './main.scss';

function App() {
  return <div>Your App</div>;
}

3. Use Components

import { Button, Typography } from '@mezzanine-ui/react';
import { PlusIcon } from '@mezzanine-ui/icons';

function App() {
  return (
    <div>
      <Typography variant="h1">Welcome to Mezzanine UI</Typography>
      <Button variant="base-primary" size="main">
        <PlusIcon />
        Click Me
      </Button>
    </div>
  );
}

4. Setup CalendarConfigProvider (Required for Date Components)

If your application uses date-related components (DatePicker, DateRangePicker, Calendar, TimePicker, etc.), you must wrap your app with a CalendarConfigProvider. This provider configures the date library and locale settings.

Choose one of the following date libraries based on your project needs:

Using Day.js (Recommended - Lightweight)

yarn add dayjs
import { CalendarConfigProviderDayjs, CalendarLocale } from '@mezzanine-ui/react/dayjs';

function App({ children }) {
  return <CalendarConfigProviderDayjs locale={CalendarLocale.ZH_TW}>{children}</CalendarConfigProviderDayjs>;
}

Using Moment.js

yarn add moment
import { CalendarConfigProviderMoment, CalendarLocale } from '@mezzanine-ui/react/moment';

function App({ children }) {
  return <CalendarConfigProviderMoment locale={CalendarLocale.ZH_TW}>{children}</CalendarConfigProviderMoment>;
}

Using Luxon

yarn add luxon
import { CalendarConfigProviderLuxon, CalendarLocale } from '@mezzanine-ui/react/luxon';

function App({ children }) {
  return <CalendarConfigProviderLuxon locale={CalendarLocale.ZH_TW}>{children}</CalendarConfigProviderLuxon>;
}

⚠️ Important: Import the provider from the specific entry point (e.g., @mezzanine-ui/react/dayjs) to avoid bundling unused date libraries.


📅 CalendarConfigProvider Configuration

Available Props

Prop Type Default Description
locale CalendarLocaleValue CalendarLocale.EN_US Controls calendar display: first day of week, month/weekday names
defaultDateFormat string 'YYYY-MM-DD' Default format string for date values
defaultTimeFormat string 'HH:mm:ss' Default format string for time values

Supported Locales

Common locale values (see CalendarLocale enum for full list):

Locale Value First Day of Week
CalendarLocale.EN_US 'en-US' Sunday
CalendarLocale.EN_GB 'en-GB' Monday
CalendarLocale.ZH_TW 'zh-TW' Sunday
CalendarLocale.ZH_CN 'zh-CN' Monday
CalendarLocale.JA_JP 'ja-JP' Sunday
CalendarLocale.KO_KR 'ko-KR' Sunday
CalendarLocale.DE_DE 'de-DE' Monday
CalendarLocale.FR_FR 'fr-FR' Monday

Usage with Next.js App Router

For Next.js App Router, place the provider in your root layout:

// app/layout.tsx
import { CalendarConfigProviderDayjs, CalendarLocale } from '@mezzanine-ui/react/dayjs';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <CalendarConfigProviderDayjs locale={CalendarLocale.ZH_TW}>{children}</CalendarConfigProviderDayjs>
      </body>
    </html>
  );
}

Custom Date/Time Formats

import { CalendarConfigProviderDayjs, CalendarLocale } from '@mezzanine-ui/react/dayjs';

function App({ children }) {
  return (
    <CalendarConfigProviderDayjs defaultDateFormat="YYYY/MM/DD" defaultTimeFormat="HH:mm" locale={CalendarLocale.ZH_TW}>
      {children}
    </CalendarConfigProviderDayjs>
  );
}

Date Library Comparison

Library Bundle Size Tree-Shakeable ISO Week Support Note
Day.js ~2KB Yes Yes Recommended for most projects
Moment ~70KB No Yes Legacy support
Luxon ~20KB Yes Yes (ISO only) Always uses Monday as first day

🎨 Design System Customization

Understanding Primitives vs Semantic

Mezzanine UI v2 uses a two-layer design token system:

  • Primitives: Raw values (e.g., #3b82f6, 16px)
  • Semantic: Contextual tokens that reference primitives (e.g., text-brand, padding-base)

💡 Best Practice: Always use semantic tokens in your application for automatic theme switching support.

Customize Color Palette

Override palette colors by passing a custom configuration:

@use '~@mezzanine-ui/system' as mzn-system;

$custom-palette: (
  background: (
    base: (
      light: #000,
      dark: #fff,
    ),
    menu: (
      light: #fff,
      dark: #9a9a9a,
    ),
    // ...
  ), // ...
);

:root {
  @include mzn-system.palette-variables(light, $custom-palette);
}

[data-theme='dark'] {
  @include mzn-system.palette-variables(dark, $custom-palette);
}

Customize Typography

Override typography settings:

@use '~@mezzanine-ui/system' as mzn-system;
@use '~@mezzanine-ui/system/typography' as typography;

$custom-variables: (
  typography: (
    h3: (
      font-size: 18px,
      font-weight: 700,
      line-height: 26px,
      letter-spacing: 0,
    ),
    // ...
  ),
);

:root {
  @include mzn-system.common-variables(default, $custom-variables);
}

Customize Spacing

Override spacing values:

@use '~@mezzanine-ui/system' as mzn-system;

$custom-variables: (
  spacing: (
    size: (
      element: (
        hairline: (
          default: 2px,
          compact: 2px,
        ),
      ),
    ),
  ),
);

:root {
  @include mzn-system.common-variables(default, $custom-variables);
}

[data-density='compact'] {
  @include mzn-system.common-variables(compact, $custom-variables);
}

🎯 Using Design Tokens in Your Components

In SCSS

@use '~@mezzanine-ui/system/palette' as palette;
@use '~@mezzanine-ui/system/spacing' as spacing;
@use '~@mezzanine-ui/system/radius' as radius;
@use '~@mezzanine-ui/system/typography' as typography;

.my-component {
  // Colors - use semantic variables
  color: palette.semantic-variable(text, brand);
  background-color: palette.semantic-variable(background, base);
  border-color: palette.semantic-variable(border, neutral);

  // Spacing - use semantic variables
  padding: spacing.semantic-variable(padding, horizontal, base);
  gap: spacing.semantic-variable(gap, tight);

  // Border radius
  border-radius: radius.variable(base);

  // Typography - apply full semantic typography
  @include typography.semantic-variable(body);
}

Available System Modules

Module Purpose Example
palette Colors (text, background, etc.) palette.semantic-variable(text, brand)
spacing Padding, margin, gap spacing.semantic-variable(padding, base)
radius Border radius radius.variable(base)
typography Font settings @include typography.semantic-variable(button)
effect Shadows, focus rings effect.variable(focus, primary)
size Element sizes size.semantic-variable(element, main)

🔧 Using React Components

Component Examples

Button

import { Button } from '@mezzanine-ui/react';
import { PlusIcon } from '@mezzanine-ui/icons';

<Button variant="base-primary" size="main">
  Primary Button
</Button>

<Button variant="base-secondary" size="sub" disabled>
  Disabled Button
</Button>

<Button variant="outlined-primary" size="minor">
  <PlusIcon />
  With Icon
</Button>

Typography

import { Typography } from '@mezzanine-ui/react';

<Typography variant="h1">Heading 1</Typography>
<Typography variant="body">Body text</Typography>
<Typography variant="caption" color="text-neutral">
  Caption text
</Typography>

DatePicker

Requires CalendarConfigProvider wrapper (see Setup CalendarConfigProvider)

import { useState } from 'react';
import { DatePicker } from '@mezzanine-ui/react';

function Example() {
  const [date, setDate] = useState<string>();

  return (
    <DatePicker
      onChange={setDate}
      placeholder="Select a date"
      value={date}
    />
  );
}

DateRangePicker

import { useState } from 'react';
import { DateRangePicker } from '@mezzanine-ui/react';

function Example() {
  const [range, setRange] = useState<[string, string]>();

  return (
    <DateRangePicker
      onChange={setRange}
      value={range}
    />
  );
}

Layout

Layout is the top-level page shell for building full-application frames. It manages a responsive structure with a sticky navigation sidebar and optional resizable side panels. The sub-components (Layout.Main, Layout.LeftPanel, Layout.RightPanel) can be placed in any order — the layout always renders them in the correct visual sequence.

Sub-component Purpose
<Navigation> Sticky left navigation sidebar
<Layout.Main> Main scrollable content area (required)
<Layout.LeftPanel> Resizable left panel (optional)
<Layout.RightPanel> Resizable right panel (optional)

Basic layout with navigation:

import { useState } from 'react';
import { Layout, Navigation, NavigationFooter, NavigationHeader, NavigationOption } from '@mezzanine-ui/react';
import { FileIcon, HomeIcon } from '@mezzanine-ui/icons';

function App() {
  const [activatedPath, setActivatedPath] = useState(['Home']);

  return (
    <Layout>
      <Navigation activatedPath={activatedPath} onOptionClick={(path) => path && setActivatedPath(path)}>
        <NavigationHeader title="My App" />
        <NavigationOption icon={HomeIcon} title="Home" />
        <NavigationOption icon={FileIcon} title="Reports">
          <NavigationOption title="Traffic" />
          <NavigationOption title="Conversion" />
        </NavigationOption>
        <NavigationFooter />
      </Navigation>
      <Layout.Main>
        <h1>Page Content</h1>
      </Layout.Main>
    </Layout>
  );
}

With a toggleable right panel:

import { useState } from 'react';
import { Layout, Navigation, NavigationFooter, NavigationHeader } from '@mezzanine-ui/react';

function App() {
  const [rightOpen, setRightOpen] = useState(false);

  return (
    <Layout>
      <Navigation>
        <NavigationHeader title="My App" />
        <NavigationFooter />
      </Navigation>
      <Layout.Main>
        <button onClick={() => setRightOpen(true)}>Open Details</button>
      </Layout.Main>
      <Layout.RightPanel defaultWidth={320} open={rightOpen}>
        <div>
          <h2>Details</h2>
          <button onClick={() => setRightOpen(false)}>Close</button>
        </div>
      </Layout.RightPanel>
    </Layout>
  );
}

With dual panels (left + right):

import { useState } from 'react';
import { Layout, Navigation, NavigationFooter, NavigationHeader } from '@mezzanine-ui/react';

function App() {
  const [leftOpen, setLeftOpen] = useState(true);
  const [rightOpen, setRightOpen] = useState(false);

  return (
    <Layout>
      <Navigation>
        <NavigationHeader title="My App" />
        <NavigationFooter />
      </Navigation>
      <Layout.LeftPanel defaultWidth={240} open={leftOpen}>
        <div>Sidebar filters, navigation trees, etc.</div>
      </Layout.LeftPanel>
      <Layout.Main>
        <h1>Main Content</h1>
        {!rightOpen && <button onClick={() => setRightOpen(true)}>Open Right</button>}
      </Layout.Main>
      <Layout.RightPanel defaultWidth={320} open={rightOpen}>
        <div>Detail view, preview, contextual actions, etc.</div>
      </Layout.RightPanel>
    </Layout>
  );
}

Layout.LeftPanel / Layout.RightPanel props:

Prop Type Default Description
open boolean false Controls panel visibility
defaultWidth number 320 Initial width in px (minimum 240)
onWidthChange (width: number) => void Callback when the panel is resized
scrollbarProps ScrollbarProps Props forwarded to the inner scrollbar

Panels are resizable by dragging the divider. Focus the divider and use / arrow keys to resize with keyboard.


🪝 React Hooks

Mezzanine provides several utility hooks for common UI patterns:

Hook Description
useClickAway Detect clicks outside an element (useful for dropdowns, modals)
useComposeRefs Compose multiple refs into one
useDocumentEscapeKeyDown Listen for ESC key press on document
useDocumentTabKeyDown Listen for Tab key press on document
useDocumentEvents Generic document event listener with cleanup
useElementHeight Track an element's height with ResizeObserver
useIsomorphicLayoutEffect SSR-safe useLayoutEffect (uses useEffect on server)
useLastCallback Stable callback reference that always calls the latest version
useLastValue Ref that always holds the latest value
usePreviousValue Access the previous render's value
useScrollLock Lock body scroll (for modals/overlays) with scrollbar gap compensation
useTopStack Manage stacking order for overlays
useWindowWidth Track window width with resize listener

Example: useClickAway

import { useRef } from 'react';
import { useClickAway } from '@mezzanine-ui/react';

function Dropdown({ onClose }) {
  const dropdownRef = useRef();

  useClickAway(() => (event) => onClose(event), dropdownRef, [onClose]);

  return <div ref={dropdownRef}>Dropdown content</div>;
}

Example: useScrollLock

import { useScrollLock } from '@mezzanine-ui/react';

function Modal({ isOpen }) {
  // Automatically locks scroll when modal is open
  useScrollLock({ enabled: isOpen });

  return isOpen ? <div className="modal">Modal content</div> : null;
}

🛠️ Utility Functions

Mezzanine also exports commonly used utility functions:

Utility Description
formatNumberWithCommas Format numbers with locale-aware thousands separators
parseNumberWithCommas Parse comma-formatted string back to number
getCSSVariableValue Get computed CSS variable value from :root
getNumericCSSVariablePixelValue Get CSS variable as numeric pixel value
arrayMove Move array item from one index to another (immutable)
cx Classname utility (re-exported from clsx)
composeRefs Compose multiple refs (non-hook version)
getScrollbarWidth Get current scrollbar width in pixels

Example: Number Formatting

import { formatNumberWithCommas, parseNumberWithCommas } from '@mezzanine-ui/react';

// Format number for display
formatNumberWithCommas(1234567); // '1,234,567'
formatNumberWithCommas(1234567, 'de-DE'); // '1.234.567'

// Parse back to number
parseNumberWithCommas('1,234,567'); // 1234567

Example: CSS Variables

import { getCSSVariableValue } from '@mezzanine-ui/react';

// Read design token values at runtime
const brandColor = getCSSVariableValue('--mzn-color-text-brand');

🌙 Theme Support

Light/Dark Mode

Mezzanine UI v2 has built-in support for light and dark modes:

// In your SCSS
:root {
  @include mzn-system.palette-variables(light);
}

[data-theme='dark'] {
  @include mzn-system.palette-variables(dark);
}

Toggle theme in your React app:

function ThemeToggle() {
  const [theme, setTheme] = useState('light');

  useEffect(() => {
    document.documentElement.setAttribute('data-theme', theme);
  }, [theme]);

  return <Button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>Toggle Theme</Button>;
}

Default/Compact Mode

Switch between comfortable and compact spacing:

:root {
  @include mzn-system.common-variables(default);
}

[data-density='compact'] {
  @include mzn-system.common-variables(compact);
}

Toggle density in your React app:

function DensityToggle() {
  const [density, setDensity] = useState('default');

  useEffect(() => {
    document.documentElement.setAttribute('data-density', density);
  }, [density]);

  return <Button onClick={() => setDensity(density === 'default' ? 'compact' : 'default')}>Toggle Density</Button>;
}

📖 Icon Usage

Use icons from the @mezzanine-ui/icons package:

import { ChevronDownIcon, PlusIcon, CheckIcon } from '@mezzanine-ui/icons';

function Example() {
  return (
    <div>
      <ChevronDownIcon />
      <PlusIcon />
      <CheckIcon />
    </div>
  );
}

🤝 Contributing

We welcome contributions! Please see our Development Guidelines for:

  • Setting up the development environment
  • Understanding the project architecture
  • Following coding conventions
  • Writing tests and documentation

📝 License

MIT License - see LICENSE for details.


🔗 Links

About

An enterprise-class UI design language and React UI library

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages