@tekton-ui/ui
v0.3.3
Published
Tekton UI Reference Component Library
Maintainers
Readme
@tekton/ui
Tekton UI Reference Component Library - High-quality, accessible React components with CSS Variables theming.
Overview
@tekton/ui provides 20 production-ready components + 13 screen templates built with:
- Screen Templates (NEW): 13 full-page layouts for rapid development
- React 19 - Latest React features with Server Components support
- TypeScript 5.7+ - Full type safety with strict mode
- Radix UI v1.0+ - Accessible headless primitives
- CSS Variables - 3-layer architecture (Atomic → Semantic → Component)
- WCAG 2.1 AA - Fully accessible
Installation
pnpm add @tekton/ui
# or
npm install @tekton/ui
# or
yarn add @tekton/uiQuick Start
Import Components
import { Button, Input, Card } from '@tekton/ui';
import '@tekton/ui/styles';
export default function App() {
return (
<Card>
<CardHeader>
<CardTitle>Welcome to Tekton UI</CardTitle>
<CardDescription>Build accessible UIs faster</CardDescription>
</CardHeader>
<CardContent>
<Input placeholder="Enter your email..." />
</CardContent>
<CardFooter>
<Button variant="primary">Get Started</Button>
</CardFooter>
</Card>
);
}CSS Variables Theming
Import the CSS Variables template and customize:
@import '@tekton/ui/styles';
:root {
/* Button Tokens */
--button-primary-background: #3b82f6;
--button-primary-foreground: white;
/* Input Tokens */
--input-border: #d1d5db;
--input-background: white;
/* Card Tokens */
--card-background: white;
--card-border: #e5e7eb;
/* ... customize 100+ other tokens */
}Components
Primitive Components (14)
Core UI building blocks with single responsibility:
- Button - Interactive button with loading states and variants (default, primary, secondary, destructive, outline, ghost, link)
- Input - Text input with error states and type support (text, email, password, number)
- Checkbox - Checkbox with indeterminate support and form integration
- RadioGroup - Radio button groups with keyboard navigation
- Switch - Toggle switch with checked/unchecked states
- Slider - Range slider with min/max/step configuration
- Text - Polymorphic text component with size variants
- Heading - Hierarchical headings (h1-h6) with level prop
- Badge - Status badges (default, primary, secondary, destructive, outline)
- Avatar - User avatars with image/fallback support
- Progress - Progress bar with value 0-100
- Link - Navigation links (default, muted, underline variants)
- Image - Image component with alt text and optional object-fit
- List - Polymorphic list component (ul/ol)
Composed Components (6)
Complex components built from primitives:
- Card - Card container with header/content/footer structure
- Form - Form with validation context and error handling
- Modal - Dialog/modal overlay with Portal rendering
- Dropdown - Dropdown menu with keyboard navigation
- Tabs - Tabbed navigation with automatic ARIA labels
- Table - Data table with semantic HTML structure
Component Examples
Button
import { Button } from '@tekton/ui';
// Variants
<Button variant="default">Default</Button>
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="destructive">Delete</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
// Sizes
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
// States
<Button loading>Loading...</Button>
<Button disabled>Disabled</Button>Props:
variant:"default" | "primary" | "secondary" | "destructive" | "outline" | "ghost" | "link"size:"sm" | "md" | "lg"loading:boolean- All native
<button>props
Input
import { Input } from '@tekton/ui';
// Basic usage
<Input type="text" placeholder="Enter text..." />
<Input type="email" placeholder="Email address" />
<Input type="password" placeholder="Password" />
// With error state
<Input type="text" aria-invalid="true" />
// Disabled
<Input disabled placeholder="Disabled input" />Props:
type:"text" | "email" | "password" | "number" | "search" | "tel" | "url"- All native
<input>props
Card
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '@tekton/ui';
<Card>
<CardHeader>
<CardTitle>Card Title</CardTitle>
<CardDescription>Card description or subtitle</CardDescription>
</CardHeader>
<CardContent>
<p>Main content goes here</p>
</CardContent>
<CardFooter>
<Button>Action</Button>
</CardFooter>
</Card>;Form
import { Form, FormField, FormLabel, FormControl, FormDescription, FormMessage } from '@tekton/ui';
import { Input } from '@tekton/ui';
<Form
onSubmit={e => {
e.preventDefault(); /* handle submit */
}}
>
<FormField name="email">
<FormLabel htmlFor="email">Email</FormLabel>
<FormControl>
<Input id="email" type="email" />
</FormControl>
<FormDescription>We'll never share your email.</FormDescription>
<FormMessage name="email">Invalid email address</FormMessage>
</FormField>
</Form>;Modal (Dialog)
import {
Modal,
ModalTrigger,
ModalContent,
ModalHeader,
ModalTitle,
ModalDescription,
ModalFooter,
ModalClose,
} from '@tekton/ui';
import { Button } from '@tekton/ui';
<Modal>
<ModalTrigger asChild>
<Button>Open Modal</Button>
</ModalTrigger>
<ModalContent>
<ModalHeader>
<ModalTitle>Modal Title</ModalTitle>
<ModalDescription>Modal description text</ModalDescription>
</ModalHeader>
<div>Modal body content</div>
<ModalFooter>
<ModalClose asChild>
<Button variant="outline">Cancel</Button>
</ModalClose>
<Button variant="primary">Confirm</Button>
</ModalFooter>
</ModalContent>
</Modal>;Dropdown Menu
import {
Dropdown,
DropdownTrigger,
DropdownContent,
DropdownItem,
DropdownSeparator,
} from '@tekton/ui';
import { Button } from '@tekton/ui';
<Dropdown>
<DropdownTrigger asChild>
<Button>Open Menu</Button>
</DropdownTrigger>
<DropdownContent>
<DropdownItem onClick={() => console.log('Edit')}>Edit</DropdownItem>
<DropdownItem onClick={() => console.log('Duplicate')}>Duplicate</DropdownItem>
<DropdownSeparator />
<DropdownItem disabled>Disabled Item</DropdownItem>
<DropdownItem onClick={() => console.log('Delete')}>Delete</DropdownItem>
</DropdownContent>
</Dropdown>;Tabs
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@tekton/ui';
<Tabs defaultValue="tab1">
<TabsList>
<TabsTrigger value="tab1">Tab 1</TabsTrigger>
<TabsTrigger value="tab2">Tab 2</TabsTrigger>
<TabsTrigger value="tab3">Tab 3</TabsTrigger>
</TabsList>
<TabsContent value="tab1">
<p>Content for Tab 1</p>
</TabsContent>
<TabsContent value="tab2">
<p>Content for Tab 2</p>
</TabsContent>
<TabsContent value="tab3">
<p>Content for Tab 3</p>
</TabsContent>
</Tabs>;Checkbox
import { Checkbox } from '@tekton/ui';
// Basic checkbox
<label>
<Checkbox id="terms" />
Accept terms and conditions
</label>
// Indeterminate state
<Checkbox checked="indeterminate" />
// Disabled
<Checkbox disabled />Props:
checked:boolean | "indeterminate"onCheckedChange:(checked: boolean | "indeterminate") => void- All Radix UI Checkbox props
RadioGroup
import { RadioGroup, RadioGroupItem } from '@tekton/ui';
<RadioGroup defaultValue="option1">
<div>
<RadioGroupItem value="option1" id="opt1" />
<label htmlFor="opt1">Option 1</label>
</div>
<div>
<RadioGroupItem value="option2" id="opt2" />
<label htmlFor="opt2">Option 2</label>
</div>
<div>
<RadioGroupItem value="option3" id="opt3" />
<label htmlFor="opt3">Option 3</label>
</div>
</RadioGroup>;Switch
import { Switch } from '@tekton/ui';
<label>
<Switch id="notifications" />
Enable notifications
</label>
<Switch checked onCheckedChange={(checked) => console.log(checked)} />Props:
checked:booleanonCheckedChange:(checked: boolean) => void- All Radix UI Switch props
Slider
import { Slider } from '@tekton/ui';
// Basic slider
<label htmlFor="volume" id="volume-label">Volume</label>
<Slider
id="volume"
defaultValue={[50]}
min={0}
max={100}
step={1}
aria-labelledby="volume-label"
/>
// Range slider
<Slider defaultValue={[25, 75]} min={0} max={100} />Props:
defaultValue:number[]min:numbermax:numberstep:number- All Radix UI Slider props
Progress
import { Progress } from '@tekton/ui';
<Progress value={50} aria-label="Upload progress" />
<Progress value={75} aria-label="Loading" />
<Progress value={100} aria-label="Complete" />Props:
value:number(0-100)- All Radix UI Progress props
Avatar
import { Avatar, AvatarImage, AvatarFallback } from '@tekton/ui';
<Avatar>
<AvatarImage src="https://example.com/avatar.jpg" alt="John Doe" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>;Badge
import { Badge } from '@tekton/ui';
<Badge variant="default">Default</Badge>
<Badge variant="primary">Primary</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="destructive">Error</Badge>
<Badge variant="outline">Outline</Badge>Props:
variant:"default" | "primary" | "secondary" | "destructive" | "outline"
Text
import { Text } from '@tekton/ui';
// Sizes
<Text size="xs">Extra small text</Text>
<Text size="sm">Small text</Text>
<Text size="md">Medium text</Text>
<Text size="lg">Large text</Text>
// Polymorphic rendering
<Text as="p">Paragraph</Text>
<Text as="span">Inline text</Text>
<Text as="div">Block text</Text>Props:
as:"p" | "span" | "div" | "label"size:"xs" | "sm" | "md" | "lg"variant:"default" | "muted"
Heading
import { Heading } from '@tekton/ui';
<Heading level={1}>Heading 1</Heading>
<Heading level={2}>Heading 2</Heading>
<Heading level={3}>Heading 3</Heading>
<Heading level={4}>Heading 4</Heading>
<Heading level={5}>Heading 5</Heading>
<Heading level={6}>Heading 6</Heading>
// Sizes
<Heading level={1} size="sm">Small H1</Heading>
<Heading level={2} size="lg">Large H2</Heading>Props:
level:1 | 2 | 3 | 4 | 5 | 6size:"sm" | "md" | "lg"
Link
import { Link } from '@tekton/ui';
<Link href="/home" variant="default">Default Link</Link>
<Link href="/about" variant="muted">Muted Link</Link>
<Link href="/contact" variant="underline">Underlined Link</Link>Props:
href:stringvariant:"default" | "muted" | "underline"- All native
<a>props
List
import { List, ListItem } from '@tekton/ui';
// Unordered list
<List as="ul">
<ListItem>Item 1</ListItem>
<ListItem>Item 2</ListItem>
<ListItem>Item 3</ListItem>
</List>
// Ordered list
<List as="ol">
<ListItem>First item</ListItem>
<ListItem>Second item</ListItem>
<ListItem>Third item</ListItem>
</List>Props:
as:"ul" | "ol"
Image
import { Image } from '@tekton/ui';
<Image
src="https://example.com/image.jpg"
alt="Description of image"
/>
<Image
src="https://example.com/image.jpg"
alt="Cover image"
className="object-cover w-full h-64"
/>Props:
src:stringalt:string(required for accessibility)- All native
<img>props
Table
import {
Table,
TableHeader,
TableBody,
TableFooter,
TableRow,
TableHead,
TableCell,
TableCaption,
} from '@tekton/ui';
<Table>
<TableCaption>List of users</TableCaption>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
<TableHead>Role</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>John Doe</TableCell>
<TableCell>[email protected]</TableCell>
<TableCell>Admin</TableCell>
</TableRow>
<TableRow>
<TableCell>Jane Smith</TableCell>
<TableCell>[email protected]</TableCell>
<TableCell>User</TableCell>
</TableRow>
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={3}>Total: 2 users</TableCell>
</TableRow>
</TableFooter>
</Table>;Features
CSS Variables First
All themeable properties use CSS Variables:
<Button variant="primary">
{/* Uses --button-primary-background and --button-primary-foreground */}
</Button>Type-Safe Variants
Powered by class-variance-authority:
<Button variant="secondary" size="lg" loading>
Click me
</Button>Accessibility Built-In
- WCAG 2.1 AA compliant - All components pass axe-core validation
- Proper ARIA attributes - Screen reader friendly
- Keyboard navigation - Full keyboard support (Tab, Arrow keys, Enter, Escape)
- Focus management - Visible focus indicators and proper focus trapping
Zero Config Setup
Works out of the box with sensible defaults:
import { Button } from '@tekton/ui';
<Button>Just works</Button>;Screen Templates (Phase 3)
New in Phase 3: 13 Screen Templates for rapid full-screen composition.
Overview
Screen Templates provide pre-built, theme-aware full-screen layouts that combine multiple components into cohesive user experiences. Each template is registered in a centralized TemplateRegistry for easy discovery and reuse.
Features:
- 13 Pre-built Layouts: Auth (4), Core (3), Feedback (5), Dashboard (1)
- Theme-Aware: Automatically adapts to active theme via CSS Variables
- AI-Friendly: Clear customization boundaries for AI agents
- Type-Safe: Full TypeScript support with ScreenTemplate interface
- Responsive: Desktop, Tablet, Mobile layouts
Quick Start
import { templateRegistry } from '@tekton/ui/templates';
// Get all templates
const allTemplates = templateRegistry.getAll(); // 13 templates
// Get by category
const authTemplates = templateRegistry.getByCategory('auth'); // 4 templates
// Get specific template
const loginTemplate = templateRegistry.get('auth.login');Available Templates (13)
Auth Templates (4)
import {
LoginTemplate,
SignupTemplate,
ForgotPasswordTemplate,
VerificationTemplate,
} from '@tekton/ui/templates/auth';- LoginTemplate (
auth.login) - Centered login card with email/password - SignupTemplate (
auth.signup) - Registration form with terms acceptance - ForgotPasswordTemplate (
auth.forgot-password) - Password reset flow - VerificationTemplate (
auth.verification) - Email verification confirmation
Core Templates (3)
import { LandingTemplate, PreferencesTemplate, ProfileTemplate } from '@tekton/ui/templates/core';- LandingTemplate (
home.landing) - Full-width landing page with CTA - PreferencesTemplate (
settings.preferences) - Sidebar settings layout - ProfileTemplate (
account.profile) - User profile with avatar editing
Feedback Templates (5)
import {
LoadingTemplate,
ErrorTemplate,
EmptyTemplate,
ConfirmationTemplate,
SuccessTemplate,
} from '@tekton/ui/templates/feedback';- LoadingTemplate (
feedback.loading) - Loading skeleton state - ErrorTemplate (
feedback.error) - Error state with retry button - EmptyTemplate (
feedback.empty) - Empty state with CTA - ConfirmationTemplate (
feedback.confirmation) - Dialog confirmation - SuccessTemplate (
feedback.success) - Success message with next steps
Dashboard Template (1)
import { DashboardTemplate } from '@tekton/ui/templates/dashboard';- DashboardTemplate (
dashboard.overview) - Dashboard layout with sidebar
Template Features
- Type-Safe: Full TypeScript support with
ScreenTemplateinterface - AI-Friendly: Clear customization boundaries (
slots,texts,options) - Theme-Aware: CSS Variables for automatic theme adaptation
- Responsive: Breakpoint-based layouts (Desktop 1024px+, Tablet 768-1024px, Mobile <768px)
- Accessible: WCAG 2.1 AA compliance (validation in progress)
TemplateRegistry API
The TemplateRegistry provides centralized template management:
import { templateRegistry } from '@tekton/ui/templates/registry';
// Get all templates
const allTemplates = templateRegistry.getAll(); // 13 templates
// Get templates by category
const authTemplates = templateRegistry.getByCategory('auth'); // 4 templates
// Get specific template
const loginTemplate = templateRegistry.get('auth.login');
// Find by required components
const formsTemplates = templateRegistry.findByRequiredComponents(['Button', 'Input', 'Form']);Design Reference: All templates follow Claude.ai Design Philosophy - clarity, accessibility, universality.
Phase 3 Status
Completed (2026-02-01):
- ✅ Template type system (
ScreenTemplate,TemplateRegistry) - ✅ 13 templates implemented (Auth 4, Core 3, Feedback 5, Dashboard 1)
- ✅ Template registry with category filtering
- ✅ Storybook stories for all templates
- ✅ SPEC TAG annotations (TAG-UI002-001 ~ 035)
- ⚠️ Test coverage: 17.26% (improvement planned)
Next Steps:
- Test coverage to 85%+
- Accessibility validation (axe-core, WCAG 2.1 AA)
- Additional template variants
- Template preview gallery in Storybook
CSS Variables Reference
@tekton/ui uses a 3-layer CSS Variables architecture:
Layer 1: Atomic Tokens
--color-primary: #3b82f6;
--color-destructive: #ef4444;
--spacing-sm: 0.5rem;
--radius-md: 0.375rem;Layer 2: Semantic Tokens
--text-primary: var(--color-primary);
--bg-destructive: var(--color-destructive);Layer 3: Component Tokens
Button Tokens:
--button-default-background
--button-default-foreground
--button-primary-background
--button-primary-foreground
--button-secondary-background
--button-secondary-foreground
--button-destructive-background
--button-destructive-foreground
--button-outline-border
--button-outline-foreground
--button-ghost-hover-background
--button-link-foreground
--button-disabled-opacity
--button-focus-ringInput Tokens:
--input-background
--input-foreground
--input-border
--input-placeholder
--input-focus-ring
--input-disabled-background
--input-disabled-foregroundCard Tokens:
--card-background
--card-foreground
--card-borderModal Tokens:
--modal-background
--modal-border
--modal-overlay-background
--modal-title-foreground
--modal-description-foregroundForm Tokens:
--form-label-foreground
--form-message-destructive
--form-description-foregroundOther Component Tokens:
- Badge:
--badge-*-background,--badge-*-foreground,--badge-*-border - Dropdown:
--dropdown-*-background,--dropdown-item-* - Tabs:
--tabs-*-background,--tabs-trigger-* - Table:
--table-*-background,--table-border - Progress:
--progress-background,--progress-indicator-background - Slider:
--slider-track-background,--slider-thumb-* - Avatar:
--avatar-background,--avatar-foreground
Custom Theme Example
/* dark-theme.css */
@import '@tekton/ui/styles';
:root {
/* Atomic Layer */
--color-primary: #60a5fa;
--color-background: #1f2937;
--color-foreground: #f9fafb;
/* Button Layer */
--button-primary-background: var(--color-primary);
--button-primary-foreground: #000000;
--button-default-background: #374151;
--button-default-foreground: var(--color-foreground);
/* Input Layer */
--input-background: #374151;
--input-foreground: var(--color-foreground);
--input-border: #4b5563;
/* Card Layer */
--card-background: #374151;
--card-foreground: var(--color-foreground);
--card-border: #4b5563;
}Development
Setup
# Clone repository
git clone https://github.com/your-org/tekton.git
cd tekton/packages/ui
# Install dependencies (requires pnpm)
pnpm installScripts
# Run tests
pnpm test
# Run tests with coverage (target: ≥90%)
pnpm test:coverage
# Run tests in watch mode
pnpm test:watch
# Type check (TypeScript 5.7+ strict mode)
pnpm type-check
# Lint (ESLint 9)
pnpm lint
# Build (outputs to dist/)
pnpm build
# Clean build artifacts
pnpm cleanProject Structure
packages/ui/
├── src/
│ ├── primitives/ # 14 primitive components
│ │ ├── button.tsx
│ │ ├── input.tsx
│ │ ├── checkbox.tsx
│ │ └── ...
│ ├── components/ # 6 composed components
│ │ ├── card.tsx
│ │ ├── form.tsx
│ │ ├── modal.tsx
│ │ └── ...
│ ├── lib/
│ │ └── utils.ts # cn() utility
│ └── index.ts # Main export
├── __tests__/
│ ├── primitives/ # Primitive tests
│ ├── components/ # Component tests
│ ├── lib/ # Utility tests
│ └── accessibility.test.tsx # WCAG compliance
├── vitest.config.ts
├── tsconfig.json
└── package.jsonTesting
All 20 components include comprehensive test coverage:
Test Coverage (98.93%)
- Statement Coverage: 98.93%
- Branch Coverage: 95.52%
- Function Coverage: 100%
- Line Coverage: 98.93%
Test Categories
Unit Tests (Vitest + Testing Library)
- Component rendering
- Props validation
- Variant behavior
- State management
- Event handling
Accessibility Tests (vitest-axe)
- WCAG 2.1 AA compliance
- ARIA attributes
- Semantic HTML
- Color contrast (disabled in jsdom)
Keyboard Navigation Tests
- Tab navigation
- Arrow key navigation (RadioGroup, Tabs, Slider)
- Enter/Space activation
- Escape key handling (Modal, Dropdown)
User Interaction Tests (userEvent)
- Click events
- Form submissions
- Input changes
- Focus management
Running Tests
# All tests
pnpm test
# Specific file
pnpm vitest run __tests__/primitives/button.test.tsx
# Watch mode
pnpm test:watch
# Coverage report
pnpm test:coverageBrowser Support
- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
Note: Internet Explorer is not supported.
TypeScript Support
All components are fully typed with TypeScript 5.7+:
import { Button, ButtonProps } from '@tekton/ui';
// Type-safe props
const MyButton: React.FC<ButtonProps> = props => {
return <Button {...props} />;
};
// Type inference
<Button
variant="primary" // ✓ Valid
variant="invalid" // ✗ TypeScript error
size="lg" // ✓ Valid
onClick={e => {
// e is typed as MouseEvent<HTMLButtonElement>
console.log(e.currentTarget);
}}
/>;Contributing
Contributions are welcome! Please read our contributing guidelines before submitting a PR.
Development Workflow
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run tests (
pnpm test) - Run type check (
pnpm type-check) - Run linter (
pnpm lint) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
Code Quality Standards
- Test Coverage: ≥90% (currently 98.93%)
- TypeScript: Strict mode, no
anytypes - Accessibility: WCAG 2.1 AA compliant
- ESLint: Zero warnings/errors
- Documentation: All public APIs documented
License
MIT License - see LICENSE for details
Links
- Documentation: Tekton UI Guide
- Radix UI: https://www.radix-ui.com/
- WCAG 2.1: https://www.w3.org/WAI/WCAG21/quickref/
- React 19: https://react.dev/
- TypeScript: https://www.typescriptlang.org/
Acknowledgments
Built with:
- React 19 - UI library
- Radix UI - Accessible primitives
- class-variance-authority - Variant management
- Vitest - Testing framework
- axe-core - Accessibility testing
Version: 1.0.0 Last Updated: 2026-01-26 Maintained by: Tekton Team
