
Security News
arXiv Is Rate Limiting Authors Following a Flood of AI Slop Submissions
arXiv now limits authors to two submissions a month as AI slop overwhelms moderators, delays good papers, and sparks debate over applying the limit to everyone.
@framingui/ui
Advanced tools
FramingUI Reference Component Library - High-quality, accessible React components with CSS Variables theming.
@framingui provides 20 production-ready components + 13 screen templates built with:
pnpm add @framingui
# or
yarn add @framingui
import { Button, Input, Card } from '@framingui';
import '@framingui/styles';
export default function App() {
return (
<Card>
<CardHeader>
<CardTitle>Welcome to FramingUI</CardTitle>
<CardDescription>Build accessible UIs faster</CardDescription>
</CardHeader>
<CardContent>
<Input placeholder="Enter your email..." />
</CardContent>
<CardFooter>
<Button variant="primary">Get Started</Button>
</CardFooter>
</Card>
);
}
Import the CSS Variables template and customize:
@import '@framingui/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 */
}
Core UI building blocks with single responsibility:
Complex components built from primitives:
import { Button } from '@framingui';
// 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<button> propsimport { Input } from '@framingui';
// 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"<input> propsimport { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '@framingui';
<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>;
import { Form, FormField, FormLabel, FormControl, FormDescription, FormMessage } from '@framingui';
import { Input } from '@framingui';
<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>;
import {
Modal,
ModalTrigger,
ModalContent,
ModalHeader,
ModalTitle,
ModalDescription,
ModalFooter,
ModalClose,
} from '@framingui';
import { Button } from '@framingui';
<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>;
import {
Dropdown,
DropdownTrigger,
DropdownContent,
DropdownItem,
DropdownSeparator,
} from '@framingui';
import { Button } from '@framingui';
<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>;
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@framingui';
<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>;
import { Checkbox } from '@framingui';
// 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") => voidimport { RadioGroup, RadioGroupItem } from '@framingui';
<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>;
import { Switch } from '@framingui';
<label>
<Switch id="notifications" />
Enable notifications
</label>
<Switch checked onCheckedChange={(checked) => console.log(checked)} />
Props:
checked: booleanonCheckedChange: (checked: boolean) => voidimport { Slider } from '@framingui';
// 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: numberimport { Progress } from '@framingui';
<Progress value={50} aria-label="Upload progress" />
<Progress value={75} aria-label="Loading" />
<Progress value={100} aria-label="Complete" />
Props:
value: number (0-100)import { Avatar, AvatarImage, AvatarFallback } from '@framingui';
<Avatar>
<AvatarImage src="https://example.com/avatar.jpg" alt="John Doe" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>;
import { Badge } from '@framingui';
<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"import { Text } from '@framingui';
// 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"import { Heading } from '@framingui';
<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"import { Link } from '@framingui';
<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"<a> propsimport { List, ListItem } from '@framingui';
// 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"import { Image } from '@framingui';
<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)<img> propsimport {
Table,
TableHeader,
TableBody,
TableFooter,
TableRow,
TableHead,
TableCell,
TableCaption,
} from '@framingui';
<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>john@example.com</TableCell>
<TableCell>Admin</TableCell>
</TableRow>
<TableRow>
<TableCell>Jane Smith</TableCell>
<TableCell>jane@example.com</TableCell>
<TableCell>User</TableCell>
</TableRow>
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={3}>Total: 2 users</TableCell>
</TableRow>
</TableFooter>
</Table>;
All themeable properties use CSS Variables:
<Button variant="primary">
{/* Uses --button-primary-background and --button-primary-foreground */}
</Button>
Powered by class-variance-authority:
<Button variant="secondary" size="lg" loading>
Click me
</Button>
Works out of the box with sensible defaults:
import { Button } from '@framingui';
<Button>Just works</Button>;
New in Phase 3: 13 Screen Templates for rapid full-screen composition.
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:
import { templateRegistry } from '@framingui/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');
import {
LoginTemplate,
SignupTemplate,
ForgotPasswordTemplate,
VerificationTemplate,
} from '@framingui/templates/auth';
auth.login) - Centered login card with email/passwordauth.signup) - Registration form with terms acceptanceauth.forgot-password) - Password reset flowauth.verification) - Email verification confirmationimport { LandingTemplate, PreferencesTemplate, ProfileTemplate } from '@framingui/templates/core';
home.landing) - Full-width landing page with CTAsettings.preferences) - Sidebar settings layoutaccount.profile) - User profile with avatar editingimport {
LoadingTemplate,
ErrorTemplate,
EmptyTemplate,
ConfirmationTemplate,
SuccessTemplate,
} from '@framingui/templates/feedback';
feedback.loading) - Loading skeleton statefeedback.error) - Error state with retry buttonfeedback.empty) - Empty state with CTAfeedback.confirmation) - Dialog confirmationfeedback.success) - Success message with next stepsimport { DashboardTemplate } from '@framingui/templates/dashboard';
dashboard.overview) - Dashboard layout with sidebarScreenTemplate interfaceslots, texts, options)The TemplateRegistry provides centralized template management:
import { templateRegistry } from '@framingui/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.
Completed (2026-02-01):
ScreenTemplate, TemplateRegistry)Next Steps:
@framingui uses a 3-layer CSS Variables architecture:
--color-primary: #3b82f6;
--color-destructive: #ef4444;
--spacing-sm: 0.5rem;
--radius-md: 0.375rem;
--text-primary: var(--color-primary);
--bg-destructive: var(--color-destructive);
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-ring
Input Tokens:
--input-background
--input-foreground
--input-border
--input-placeholder
--input-focus-ring
--input-disabled-background
--input-disabled-foreground
Card Tokens:
--card-background
--card-foreground
--card-border
Modal Tokens:
--modal-background
--modal-border
--modal-overlay-background
--modal-title-foreground
--modal-description-foreground
Form Tokens:
--form-label-foreground
--form-message-destructive
--form-description-foreground
Other Component Tokens:
--badge-*-background, --badge-*-foreground, --badge-*-border--dropdown-*-background, --dropdown-item-*--tabs-*-background, --tabs-trigger-*--table-*-background, --table-border--progress-background, --progress-indicator-background--slider-track-background, --slider-thumb-*--avatar-background, --avatar-foreground/* dark-theme.css */
@import '@framingui/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;
}
# Clone repository
git clone https://github.com/your-org/tekton.git
cd tekton/packages/ui
# Install dependencies (requires pnpm)
pnpm install
# 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 clean
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.json
All 20 components include comprehensive test coverage:
Unit Tests (Vitest + Testing Library)
Accessibility Tests (vitest-axe)
Keyboard Navigation Tests
User Interaction Tests (userEvent)
# All tests
pnpm test
# Specific file
pnpm vitest run __tests__/primitives/button.test.tsx
# Watch mode
pnpm test:watch
# Coverage report
pnpm test:coverage
Note: Internet Explorer is not supported.
All components are fully typed with TypeScript 5.7+:
import { Button, ButtonProps } from '@framingui';
// 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);
}}
/>;
Contributions are welcome! Please read our contributing guidelines before submitting a PR.
git checkout -b feature/amazing-feature)pnpm test)pnpm type-check)pnpm lint)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)any typesMIT License - see LICENSE for details
Built with:
Version: 1.0.0 Last Updated: 2026-01-26 Maintained by: Tekton Team
FAQs
FramingUI Reference Component Library
The npm package @framingui/ui receives a total of 0 weekly downloads. As such, @framingui/ui popularity was classified as not popular.
We found that @framingui/ui demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
arXiv now limits authors to two submissions a month as AI slop overwhelms moderators, delays good papers, and sparks debate over applying the limit to everyone.

Research
/Security News
A new GhostAction wave hits hundreds of GitHub repos, expanding CI/CD secret theft to cloud and AI credentials in source code and git history.

Research
/Security News
Tensorlake npm SDK version 0.5.144 was compromised in a ChainDrop / Shai-Hulud attack, delivering credential-stealing malware.