๐Ÿ”Œ Plugin UI System

React Components Library

@gauzy/ui-react-components is a pure React component library providing UI primitives for building plugin widgets. It has no Angular or plugin-system dependencies โ€” it's pure React + TypeScript.

Installation

pnpm add @gauzy/ui-react-components

Import

import { Card, CardHeader, CardTitle, CardContent, Progress, theme } from '@gauzy/ui-react-components';

Design Tokens

All components use a shared theme object that matches the Nebular/NbCard aesthetic of the Angular host application.

import { theme } from '@gauzy/ui-react-components';

theme.textPrimary   // '#222b45'   โ€” primary text
theme.textSecondary // '#8f9bb3'   โ€” secondary/hint text
theme.textHint      // '#c5cee0'   โ€” lightest text for decorative elements
theme.bg            // '#ffffff'   โ€” card background (default variant)
theme.bgCard2       // 'rgba(50, 50, 50, 0.02)' โ€” tinted background (accent variant)
theme.border        // '#edf1f7'   โ€” border color
theme.blue          // '#3366ff'   โ€” blue accent
theme.red           // '#ff3d71'   โ€” red accent
theme.orange        // '#ffaa00'   โ€” orange accent
theme.green         // '#00d68f'   โ€” green accent
theme.shadow        // '0 0.5rem 1rem 0 rgba(44, 51, 73, 0.08)'    โ€” default card shadow
theme.shadowLight   // '0px 6px 20px 0px rgba(0, 0, 0, 0.05)'     โ€” light variant shadow
theme.radius        // '0.5rem'    โ€” border radius (8px)
theme.font          // "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"

Use these tokens in your components for visual consistency with the Angular UI:

const MyWidget = () => (
  <div style={{ color: theme.textPrimary, fontFamily: theme.font }}>
    <span style={{ color: theme.green }}>Active</span>
  </div>
);

Card (Compound Components)

The Card system uses a shadcn-style compound component pattern for flexible, composable card layouts.

Basic Usage

import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '@gauzy/ui-react-components';

function MyWidget() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Weekly Summary</CardTitle>
        <CardDescription>Time tracked this week</CardDescription>
      </CardHeader>
      <CardContent>
        <p>42 hours tracked across 5 projects</p>
      </CardContent>
      <CardFooter>
        <button>View Details</button>
      </CardFooter>
    </Card>
  );
}

With Actions

import { Card, CardHeader, CardTitle, CardAction, CardContent } from '@gauzy/ui-react-components';

function SettingsCard() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Notifications</CardTitle>
        <CardAction>
          <button onClick={handleReset}>Reset</button>
          <button onClick={handleSave}>Save</button>
        </CardAction>
      </CardHeader>
      <CardContent>
        {/* settings form */}
      </CardContent>
    </Card>
  );
}

Accent Variant

<Card variant="accent">
  <CardContent>
    Tinted background with lighter shadow
  </CardContent>
</Card>

Component Reference

Card

Root container. All other Card components are optional children.

interface CardProps {
  children?: ReactNode;
  variant?: 'default' | 'accent';
  style?: CSSProperties;
  className?: string;
}
VariantBackgroundShadow
default#ffffff0 0.5rem 1rem 0 rgba(44, 51, 73, 0.08)
accentrgba(50, 50, 50, 0.02)0px 6px 20px 0px rgba(0, 0, 0, 0.05)

Both variants share: 1px solid #edf1f7 border, 0.5rem border-radius, overflow: hidden.

CardHeader

Header section with bottom border separator. Uses relative positioning so CardAction can position absolutely.

interface CardHeaderProps {
  children?: ReactNode;
  style?: CSSProperties;
  className?: string;
}
  • Layout: flex column, gap 0.375rem
  • Padding: 1rem 1.25rem
  • Bottom border: 1px solid #edf1f7

CardTitle

Rendered as <h3>.

interface CardTitleProps {
  children?: ReactNode;
  style?: CSSProperties;
  className?: string;
}
  • Font-size: 1.125rem (18px), weight: 600
  • Color: #222b45

CardDescription

Rendered as <p>. Secondary text beneath the title.

interface CardDescriptionProps {
  children?: ReactNode;
  style?: CSSProperties;
  className?: string;
}
  • Font-size: 0.8125rem (13px)
  • Color: #8f9bb3

CardAction

Positioned absolutely in the top-right corner of CardHeader. Must be a direct child of CardHeader.

interface CardActionProps {
  children?: ReactNode;
  style?: CSSProperties;
  className?: string;
}
  • Position: absolute, top 1rem, right 1.25rem
  • Layout: flex row, gap 0.5rem

CardContent

Main body content section.

interface CardContentProps {
  children?: ReactNode;
  style?: CSSProperties;
  className?: string;
}
  • Padding: 1rem 1.25rem

CardFooter

Footer section with top border separator.

interface CardFooterProps {
  children?: ReactNode;
  style?: CSSProperties;
  className?: string;
}
  • Layout: flex row, center-aligned
  • Padding: 1rem 1.25rem
  • Top border: 1px solid #edf1f7

WidgetCard

A pre-styled stat/metric card built on Card + CardContent. Designed for dashboard widget use cases.

interface WidgetCardProps {
  label: string;              // Stat label (secondary text)
  value: string | number;     // Stat value (primary display)
  loading?: boolean;          // Shows em-dash and hint color when true
  children?: ReactNode;       // Optional content below value
}

Usage

import { WidgetCard } from '@gauzy/ui-react-components';

<WidgetCard label="Hours Today" value="6h 32m" />
<WidgetCard label="Activity" value="78%" loading={isLoading} />
<WidgetCard label="Team Members" value={12}>
  <ColorDots count={12} />
</WidgetCard>

Layout

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Stat Label              โ‹ฎ   โ”‚  โ† label (13px, secondary color) + decorative ellipsis
โ”‚                              โ”‚
โ”‚ 6h 32m                       โ”‚  โ† value (30px, bold, -0.02em letter-spacing)
โ”‚ [optional children]          โ”‚  โ† children slot
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  • Loading state: shows em-dash (โ€”) in hint color instead of value
  • Min-width: 140px, flex: 1 1 0 (responsive flex grow)

Progress

A linear progress bar with smooth animation.

interface ProgressProps {
  percent: number;    // 0โ€“100 (clamped)
  color: string;      // Foreground color (e.g., theme.blue)
}

Usage

import { Progress, theme } from '@gauzy/ui-react-components';

<Progress percent={75} color={theme.green} />
<Progress percent={30} color={theme.orange} />
<Progress percent={90} color={theme.blue} />

Styling

  • Track: 4px tall, #edf1f7 background, 2px border-radius
  • Fill: animated width transition (0.4s ease), custom color
  • Values are clamped to 0โ€“100%

ColorDots

Renders a row of colored circular dots โ€” useful for visual count indicators.

interface ColorDotsProps {
  count: number;         // Number of dots to render
  colors?: string[];     // Custom color array (cycles for count > length)
}

Default Colors

['#ffaa00', '#ff6b35', '#ffcc02', '#ff8c00', '#ffd700']

Usage

import { ColorDots } from '@gauzy/ui-react-components';

<ColorDots count={5} />
<ColorDots count={8} colors={[theme.blue, theme.green, theme.orange]} />

Styling

  • Dot size: 10px ร— 10px circles
  • Gap: 0.3rem (4.8px)
  • Colors cycle: colors[i % colors.length]

Utility Functions

formatDuration

Converts seconds to HH:mm:ss format.

function formatDuration(totalSeconds: number): string
import { formatDuration } from '@gauzy/ui-react-components';

formatDuration(3661)   // "01:01:01"
formatDuration(7200)   // "02:00:00"
formatDuration(45)     // "00:00:45"
formatDuration(0)      // "00:00:00"
  • Input clamped to >= 0
  • Always returns zero-padded two-digit segments

currentWeekRange

Returns the current week's date range (Mondayโ€“Sunday).

function currentWeekRange(): { startDate: Date; endDate: Date }
import { currentWeekRange } from '@gauzy/ui-react-components';

const { startDate, endDate } = currentWeekRange();
// startDate: Monday 00:00:00.000
// endDate:   Sunday 23:59:59.999

todayRange

Returns today's date range.

function todayRange(): { todayStart: Date; todayEnd: Date }
import { todayRange } from '@gauzy/ui-react-components';

const { todayStart, todayEnd } = todayRange();
// todayStart: today 00:00:00.000
// todayEnd:   today 23:59:59.999

Full Example: Dashboard Widget

import {
  Card, CardHeader, CardTitle, CardDescription, CardAction, CardContent,
  WidgetCard, Progress, ColorDots,
  theme, formatDuration
} from '@gauzy/ui-react-components';
import { useTranslation, usePluginSetting } from '@gauzy/ui-react';

export function TimeTrackingDashboard() {
  const { t } = useTranslation();
  const showMembers = usePluginSetting<boolean>('my-plugin', 'showMembers', true);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
      {/* Stat cards row */}
      <div style={{ display: 'flex', gap: '0.75rem', flexWrap: 'wrap' }}>
        <WidgetCard label={t('WORKED_TODAY')} value={formatDuration(23400)} />
        <WidgetCard label={t('ACTIVITY')} value="76%" />
        <WidgetCard label={t('PROJECTS')} value={5}>
          <ColorDots count={5} />
        </WidgetCard>
      </div>

      {/* Detail card */}
      {showMembers && (
        <Card>
          <CardHeader>
            <CardTitle>{t('TEAM_ACTIVITY')}</CardTitle>
            <CardDescription>This week's progress</CardDescription>
            <CardAction>
              <button>Refresh</button>
            </CardAction>
          </CardHeader>
          <CardContent>
            <div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
              <div>
                <span>Alice</span>
                <Progress percent={85} color={theme.green} />
              </div>
              <div>
                <span>Bob</span>
                <Progress percent={62} color={theme.blue} />
              </div>
            </div>
          </CardContent>
        </Card>
      )}
    </div>
  );
}

Package Structure

packages/ui-react-components/src/
โ”œโ”€โ”€ index.ts                          # Public API
โ””โ”€โ”€ lib/
    โ”œโ”€โ”€ theme.ts                      # Design tokens
    โ”œโ”€โ”€ components/
    โ”‚   โ”œโ”€โ”€ ui/
    โ”‚   โ”‚   โ”œโ”€โ”€ index.ts              # Card compound exports
    โ”‚   โ”‚   โ”œโ”€โ”€ Card.tsx
    โ”‚   โ”‚   โ”œโ”€โ”€ CardHeader.tsx
    โ”‚   โ”‚   โ”œโ”€โ”€ CardTitle.tsx
    โ”‚   โ”‚   โ”œโ”€โ”€ CardDescription.tsx
    โ”‚   โ”‚   โ”œโ”€โ”€ CardAction.tsx
    โ”‚   โ”‚   โ”œโ”€โ”€ CardContent.tsx
    โ”‚   โ”‚   โ””โ”€โ”€ CardFooter.tsx
    โ”‚   โ”œโ”€โ”€ WidgetCard.tsx
    โ”‚   โ”œโ”€โ”€ Progress.tsx
    โ”‚   โ””โ”€โ”€ ColorDots.tsx
    โ””โ”€โ”€ helpers/
        โ”œโ”€โ”€ format-duration.ts
        โ”œโ”€โ”€ current-week-range.ts
        โ””โ”€โ”€ today-range.ts

Edit this page

Copyright ยฉ 2023-Present Ever Co. LTD.Docs by Sourcey