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-componentsImport
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;
}| Variant | Background | Shadow |
|---|---|---|
default | #ffffff | 0 0.5rem 1rem 0 rgba(44, 51, 73, 0.08) |
accent | rgba(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, right1.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,
#edf1f7background, 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): stringimport { 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.999todayRange
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.999Full 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.tsRelated
- React Bridge โ mounting React inside Angular
- Plugin Services โ events, settings, state hooks
- API Reference โ complete type reference