Skip to content

Component Catalog

Visual reference for all UI components in the design system.

Source: src/components/ui/

Quick Reference

UI Components

ComponentVariantsSizesUse Case
Buttonprimary, secondary, destructive, ghost, outlinesm, md, lg, iconActions and navigation
Inputdefault, error-Form text input
Card--Content containers
Alertdefault, success, warning, error-Status messages
Badgedefault, secondary, destructive, outline-Status labels
PasswordStrengthMeter--Password validation
FieldError--Form validation errors

SDK Components

ComponentUse CasePackage
ProtectedRouteProtect pages from unauthenticated users@soclestack/react
CanRole-based UI visibility@soclestack/react
OrganizationSwitcherMulti-tenant org switching@soclestack/react
InviteAcceptHandle invite tokens@soclestack/react
SessionTimeoutWarningWarn before session expires@soclestack/react
LoadingSpinnerLoading indicator@soclestack/react
AccessDeniedAccess denied page@soclestack/react

Button

Versatile button component for actions and navigation.

When to use:

  • primary: Main action on page (Submit, Save, Confirm)
  • secondary: Cancel, Back, or less important actions
  • destructive: Delete, Remove, or irreversible actions
  • ghost: Subtle actions, toolbar buttons, or icon-only buttons
  • outline: Alternative to secondary when more visual weight is needed

Props

PropTypeDefaultDescription
variant'primary' | 'secondary' | 'destructive' | 'ghost' | 'outline''primary'Visual style
size'sm' | 'md' | 'lg' | 'icon''md'Button size
disabledbooleanfalseDisabled state
classNamestring-Additional CSS classes

Variants

Button Variants

Sizes

Button Sizes

Usage

tsx
import { Button } from '@/components/ui/button';

// Primary action
<Button onClick={handleSubmit}>Save Changes</Button>

// Secondary action
<Button variant="secondary">Cancel</Button>

// Destructive action
<Button variant="destructive">Delete Account</Button>

// Icon button
<Button variant="ghost" size="icon">
  <Settings className="h-4 w-4" />
</Button>

// Loading state
<Button disabled>
  <Loader className="mr-2 h-4 w-4 animate-spin" />
  Saving...
</Button>

Accessibility

  • Focus ring visible on keyboard navigation
  • Disabled state prevents interaction and shows visual feedback
  • Supports aria-label for icon-only buttons

Input

Form input component with error state support.

Props

PropTypeDefaultDescription
errorbooleanfalseShows error styling
typestring'text'Input type (text, email, password, etc.)
placeholderstring-Placeholder text
disabledbooleanfalseDisabled state

States

Input States

Usage

tsx
import { Input } from '@/components/ui/input';

// Basic input
<Input
  type="email"
  placeholder="Enter your email"
  value={email}
  onChange={(e) => setEmail(e.target.value)}
/>

// With error state
<Input
  type="password"
  error={!!errors.password}
  aria-describedby="password-error"
/>

// Disabled
<Input disabled value="Cannot edit" />

Accessibility

  • Supports aria-invalid (auto-set when error is true)
  • Use aria-describedby to link to error messages
  • Focus states clearly visible

Card

Container component for grouped content with header/body structure.

Sub-components

ComponentPurpose
CardOuter container with border and shadow
CardHeaderHeader section with spacing
CardTitleMain heading (h3)
CardDescriptionSubtitle text
CardContentMain content area
CardFooterFooter with actions

Structure

Card Structure

Usage

tsx
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from '@/components/ui/card';

<Card>
  <CardHeader>
    <CardTitle>Account Settings</CardTitle>
    <CardDescription>Update your profile information</CardDescription>
  </CardHeader>
  <CardContent>
    <form>
      <Input placeholder="Name" />
      <Input placeholder="Email" />
    </form>
  </CardContent>
  <CardFooter>
    <Button variant="secondary">Cancel</Button>
    <Button>Save</Button>
  </CardFooter>
</Card>

Alert

Status message component with icon and color variants.

When to use:

  • default: General information, tips, or neutral messages
  • success: Confirmation of completed actions
  • warning: Caution about potential issues or expiring states
  • error: Failed actions or validation errors requiring attention

Props

PropTypeDefaultDescription
variant'default' | 'success' | 'warning' | 'error''default'Alert type
childrenReactNode-Alert content

Variants

Alert Variants

Usage

tsx
import { Alert } from '@/components/ui/alert';

// Success message
<Alert variant="success">
  Your password has been changed successfully.
</Alert>

// Error message
<Alert variant="error">
  Invalid credentials. Please try again.
</Alert>

// Warning
<Alert variant="warning">
  Your account will be locked after 3 more failed attempts.
</Alert>

// Information
<Alert variant="default">
  Two-factor authentication is recommended.
</Alert>

Accessibility

  • Uses role="alert" for error/warning variants
  • Uses aria-live="assertive" for errors, aria-live="polite" for others
  • Icons are decorative (aria-hidden="true")

Badge

Small status indicator labels.

When to use:

  • default: Active or positive states (Active, Enabled, Online)
  • secondary: Neutral or pending states (Pending, Draft, Idle)
  • destructive: Negative states (Expired, Revoked, Inactive)
  • outline: Labels or categories (role badges, tags)

Props

PropTypeDefaultDescription
variant'default' | 'secondary' | 'destructive' | 'outline''default'Badge style

Variants

Badge Variants

Usage

tsx
import { Badge } from '@/components/ui/badge';

// Status indicators
<Badge>Active</Badge>
<Badge variant="secondary">Pending</Badge>
<Badge variant="destructive">Expired</Badge>

// Role badges
<Badge variant="outline">{user.role}</Badge>

// In tables
<td>
  <Badge variant={key.revokedAt ? 'destructive' : 'default'}>
    {key.revokedAt ? 'Revoked' : 'Active'}
  </Badge>
</td>

PasswordStrengthMeter

Visual password strength indicator with requirements checklist.

Props

PropTypeDefaultDescription
passwordstring-Password to evaluate
showRequirementsbooleantrueShow requirements checklist
showSuggestionsbooleantrueShow improvement suggestions

Visual States

Weak Password:

Password Strength - Weak

Strong Password:

Password Strength - Strong

Usage

tsx
import { PasswordStrengthMeter } from '@/components/ui/password-strength-meter';

// Full display
<PasswordStrengthMeter password={password} />

// Minimal (just the bar)
<PasswordStrengthMeter
  password={password}
  showRequirements={false}
  showSuggestions={false}
/>

FieldError

Form field error message display.

Props

PropTypeDefaultDescription
idstring-ID for aria-describedby linking
errorstring[]-Array of error messages (displays first)

Usage

tsx
import { FieldError } from '@/components/ui/field-error';

<div>
  <label htmlFor="email">Email</label>
  <Input
    id="email"
    error={!!errors.email}
    aria-describedby="email-error"
  />
  <FieldError id="email-error" error={errors.email} />
</div>

Accessibility

  • Uses role="alert" for screen reader announcement
  • Uses aria-atomic="true" to announce entire message

Design Tokens

Colors

TokenHexUsage
Primary#2563eb (blue-600)Primary actions
Secondary#e5e7eb (gray-200)Secondary actions
Destructive#dc2626 (red-600)Destructive actions
Success#16a34a (green-600)Success states
Warning#ca8a04 (yellow-600)Warning states
Error#dc2626 (red-600)Error states

Spacing

SizeValueUsage
smh-8, px-3Compact buttons
mdh-10, px-4Default size
lgh-12, px-6Large buttons

Border Radius

All components use rounded-md (0.375rem / 6px) for consistency. Badges use rounded-full for pill shape.



SDK Components

Components from @soclestack/react for common authentication patterns.

ProtectedRoute

Protects routes from unauthenticated users with optional role requirements.

Props:

PropTypeDefaultDescription
childrenReactNoderequiredContent to protect
rolesstring[]-Required roles (any match)
fallbackReactNode<LoadingSpinner />Loading state
accessDeniedFallbackReactNode<AccessDenied />Role check failed
tsx
import { ProtectedRoute } from '@soclestack/react';

// Basic protection
<ProtectedRoute>
  <Dashboard />
</ProtectedRoute>

// With role requirement
<ProtectedRoute roles={['ROLE_ADMIN']}>
  <AdminPanel />
</ProtectedRoute>

Can

Conditionally renders children based on user roles or organization permissions.

Props:

PropTypeDefaultDescription
childrenReactNoderequiredContent to show if authorized
rolesstring[]-Global user roles
orgRolesstring[]-Organization roles
fallbackReactNodenullContent if unauthorized
tsx
import { Can } from '@soclestack/react';

// Show only to admins
<Can roles={['ROLE_ADMIN']}>
  <DeleteButton />
</Can>

// With fallback
<Can roles={['ROLE_ADMIN']} fallback={<UpgradePrompt />}>
  <PremiumFeature />
</Can>

// Organization roles
<Can orgRoles={['ROLE_OWNER', 'ROLE_ADMIN']}>
  <TeamSettings />
</Can>

OrganizationSwitcher

Dropdown for switching between organizations in multi-tenant apps.

Props:

PropTypeDefaultDescription
triggerReactNodeDefault buttonCustom trigger element
onSwitch(org: Organization) => void-Called after switching
showCreateLinkbooleanfalseShow create org link
createOrgUrlstring/organizations/newURL for create link
tsx
import { OrganizationSwitcher } from '@soclestack/react';

// Basic usage
<OrganizationSwitcher />

// With callback
<OrganizationSwitcher
  onSwitch={(org) => router.push(`/org/${org.slug}`)}
  showCreateLink
/>

InviteAccept

Handles organization invite token validation and acceptance.

Props:

PropTypeDefaultDescription
tokenstringrequiredInvite token from URL
onAccepted(org: Organization) => void-Called after accepting
onError(error: Error) => void-Called on error
loginUrlstring/loginLogin page URL
returnUrlstring-Post-login redirect

States:

StatusVisual
loadingSpinner
validInvite details + Accept button
expiredError message
invalidError message
tsx
import { InviteAccept } from '@soclestack/react';

<InviteAccept
  token={params.token}
  onAccepted={(org) => router.push(`/org/${org.slug}`)}
  onError={(error) => toast.error(error.message)}
/>

SessionTimeoutWarning

Modal that warns users before their session expires.

Props:

PropTypeDefaultDescription
warnBeforenumber300Seconds before expiry to warn
checkIntervalnumber30Check frequency (seconds)
onWarning() => void-Called when warning shown
onTimeout() => void-Called when session expires
onExtend() => void-Called after extend success
onLogout() => void-Called on logout click
titlestring"Session Expiring"Modal title
extendLabelstring"Stay Signed In"Extend button text
logoutLabelstring"Log Out"Logout button text
tsx
import { SessionTimeoutWarning } from '@soclestack/react';

// Basic - add to root layout
<SessionTimeoutWarning />

// With callbacks
<SessionTimeoutWarning
  warnBefore={300}
  onTimeout={() => router.push('/login?expired=true')}
  onExtend={() => toast.success('Session extended')}
/>

LoadingSpinner

Default loading indicator used by SDK components.

Props:

PropTypeDefaultDescription
sizenumber24Size in pixels
classNamestring-Additional CSS
tsx
import { LoadingSpinner } from '@soclestack/react';

<LoadingSpinner />
<LoadingSpinner size={32} className="text-blue-500" />

AccessDenied

Default access denied page shown by ProtectedRoute.

Props:

PropTypeDefaultDescription
titlestring"Access Denied"Heading
messagestring(default)Description text
tsx
import { AccessDenied } from '@soclestack/react';

<AccessDenied
  title="Permission Required"
  message="You need admin access to view this page."
/>