Server Components
Available via @stackmates/ui-server-components
MetricCard
KPI card with value, label, optional variant coloring and trend indicator. Supports clickable href.
Total Contacts
Active Deals
Overdue Tasks
Pipeline Value
Conversion Rate %
Browse All Contacts
MetricCardProps
| Prop | Type | Default | Description |
|---|---|---|---|
| value* | string | number | — | Primary display value |
| label* | string | — | Label below the value |
| variant | 'default' | 'success' | 'danger' | 'warning' | 'info' | 'default' | Color variant for the value |
| trend | { change?: number; label?: string; direction?: "up" | "down" } | — | Optional trend indicator with change percentage or label |
| href | string | — | Makes the entire card a clickable link |
Installation
import { MetricCard } from '@stackmates/ui-server-components';Usage
Basic
<MetricCard value={142} label="Total Contacts" />With trend
<MetricCard value={38} label="Active Deals" variant="success" trend={{ change: 12.5 }} />Accessibility
- Renders as a <div> (or <a> when href is provided)
- Value and label are visible text — no additional ARIA needed
- Trend icon is decorative — color is not the only indicator
PageHeader
Page title with optional description and action slot (children).
Contacts
Manage your organization's contacts and relationships.
Dashboard
PageHeaderProps
| Prop | Type | Default | Description |
|---|---|---|---|
| title* | string | — | Page title text |
| description | string | — | Subtitle text below the title |
| children | ReactNode | — | Action slot (buttons, links) rendered on the right |
Installation
import { PageHeader } from '@stackmates/ui-server-components';Usage
With description and action
<PageHeader title="Contacts" description="Manage contacts.">
<Button>Add Contact</Button>
</PageHeader>Accessibility
- Title renders as <h1> — one per page
- Description provides context for screen readers
Card
Compound card with header, title, description, content, and footer slots.
3 active tasks, 2 pending review.
CardProps
| Prop | Type | Default | Description |
|---|---|---|---|
| children* | ReactNode | — | Card content — compose with CardHeader, CardContent, CardFooter |
| className | string | — | Additional CSS classes |
Installation
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '@stackmates/ui-server-components';Usage
Full compound card
<Card>
<CardHeader>
<CardTitle>Title</CardTitle>
<CardDescription>Subtitle</CardDescription>
</CardHeader>
<CardContent>Content here</CardContent>
<CardFooter>Footer</CardFooter>
</Card>Accessibility
- Renders as semantic <div> — add role="region" if card is a landmark
- CardTitle should match heading hierarchy of the page
EmptyState
Empty state with title, description, optional variant illustration, and action slot.
No Contacts Yet
Add your first contact to start building relationships.
No Deals Found
Create a deal to track your sales pipeline.
EmptyStateProps
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | 'contacts' | 'deals' | 'default' | 'default' | Illustration variant |
| title* | string | — | Empty state heading |
| description* | string | — | Explanation text |
| actions | ReactNode | — | CTA button or link slot |
Installation
import { EmptyState } from '@stackmates/ui-server-components';Accessibility
- CTA within actions slot should be a <button> or <a> for keyboard access
- Illustration is decorative — hidden from screen readers
AccessDenied
403-style inline access denied. Renders in-place, not a redirect.
Access Denied
You don't have permission to access this feature. Contact your organisation admin to request access.
Go to HomeAccessDeniedProps
| Prop | Type | Default | Description |
|---|---|---|---|
| feature | string | — | Feature name shown in the denial message |
Installation
import { AccessDenied } from '@stackmates/ui-server-components';Accessibility
- Uses role="alert" to announce denial to screen readers
- Feature name provides context for the denied action
PaginationControls
URL-based pagination using Next.js Link. Handles ellipsis for large ranges.
PaginationControlsProps
| Prop | Type | Default | Description |
|---|---|---|---|
| currentPage* | number | — | Active page number (1-based) |
| totalPages* | number | — | Total number of pages |
| basePath* | string | — | URL path to append ?page=N to |
Installation
import { PaginationControls } from '@stackmates/ui-server-components';Accessibility
- Uses <nav> with aria-label="Pagination"
- Current page announced via aria-current="page"
- Previous/Next links are keyboard accessible
PaginationSummary
Text summary line for pagination context.
PaginationSummaryProps
| Prop | Type | Default | Description |
|---|---|---|---|
| text* | string | — | Summary text (e.g. "Showing 1-25 of 142") |
Installation
import { PaginationSummary } from '@stackmates/ui-server-components';Accessibility
- Renders as <p> with aria-live="polite" for dynamic updates
AlertRx
Alert banner with title and description. Supports default and destructive variants.
AlertRxProps
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | 'default' | 'destructive' | 'default' | Alert style variant |
| children* | ReactNode | — | Alert content — compose with AlertRxTitle, AlertRxDescription |
Installation
import { AlertRx, AlertRxTitle, AlertRxDescription } from '@stackmates/ui-server-components';Usage
Default
<AlertRx>
<Info className="h-4 w-4" />
<AlertRxTitle>Info</AlertRxTitle>
<AlertRxDescription>Message here</AlertRxDescription>
</AlertRx>Destructive
<AlertRx variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertRxTitle>Error</AlertRxTitle>
<AlertRxDescription>Something went wrong</AlertRxDescription>
</AlertRx>Accessibility
- Uses role="alert" for screen reader announcement
- Icon is decorative — pair with AlertRxTitle for meaning
Heading / Subheading
Semantic heading and subheading components with consistent typography.
Heading level 1
Heading level 2
Subheading level 2
Subheading level 3
HeadingProps
| Prop | Type | Default | Description |
|---|---|---|---|
| level* | 1 | 2 | 3 | 4 | 5 | 6 | — | HTML heading level (h1-h6) |
| children* | ReactNode | — | Heading text content |
Installation
import { Heading, Subheading } from '@stackmates/ui-server-components';Accessibility
- Renders semantic <h1>-<h6> elements — maintain hierarchy
- Never skip heading levels (e.g. h1 to h3 without h2)
Text / TextLink / Strong / Code
Inline typography primitives for body text, links, emphasis, and code.
Standard text paragraph rendered on the server.
With TextLink, Strong, and Code inline.
Installation
import { Text, TextLink, Strong, Code } from '@stackmates/ui-server-components';Accessibility
- TextLink renders as <a> — keyboard accessible by default
- Strong renders as <strong> — conveyed by screen readers
- Code renders as <code> — announced as code by assistive technology
ErrorMessage
Inline form error message with destructive styling.
This field is required.
Email address is not valid.
ErrorMessageProps
| Prop | Type | Default | Description |
|---|---|---|---|
| message* | string | — | Error message text to display |
Installation
import { ErrorMessage } from '@stackmates/ui-server-components';Accessibility
- Uses role="alert" for immediate screen reader announcement
- Pair with aria-describedby on the related input
Skeleton
Loading placeholder with pulse animation. Shape via className.
SkeletonProps
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | — | Width, height, and border-radius via Tailwind classes |
Installation
import { Skeleton } from '@stackmates/ui-server-components';Accessibility
- Use aria-busy="true" on the container while loading
- Provide aria-label on the skeleton region for context
Link
Next.js Link wrapper for internal navigation.
Installation
import { Link } from '@stackmates/ui-server-components';Accessibility
- Renders as <a> — keyboard accessible by default
- Link text should describe the destination, not "click here"