@components-kit/react
v0.1.1
Published
Bi-directional Figma design system sync. CSS ships instantly—no code, no redeploy, no maintenance.
Maintainers
Readme
ComponentsKit
Headless, accessible React components with data attributes for CSS-based styling
Bi-directional Figma design system sync. CSS ships instantly—no code, no redeploy, no maintenance.
Highlights
- Headless/Unstyled - Zero built-in styles, full control via
data-*attributes - Accessible - WAI-ARIA compliant with keyboard navigation support
- Zero Dependencies - Only peer dependencies (React, optional table/select libs)
- TypeScript First - Full type safety with exported interfaces
- Polymorphic - Render components as different HTML elements
- Composable -
asChildpattern for flexible component composition
Installation
npm install @components-kit/reactPeer Dependencies
# Required
npm install react react-dom
# Optional - only if using Table component
npm install @tanstack/react-table
# Optional - only if using Select component
npm install downshiftQuick Start
import { Button, Input, Heading } from "@components-kit/react";
function App() {
return (
<div>
<Heading as="h1" variantName="title">
Welcome
</Heading>
<Input
type="email"
placeholder="Enter your email"
variantName="default"
/>
<Button variantName="primary" size="md">
Get Started
</Button>
</div>
);
}Styling Setup
ComponentsKit components are headless (unstyled). To apply styles, load the CSS bundle from the ComponentsKit API.
1. Get Your API Key
Sign up at componentskit.com to get your API key.
2. Environment Variables
Create a .env file in your project root:
# For Next.js
NEXT_PUBLIC_COMPONENTS_KIT_URL=https://api.componentskit.com
NEXT_PUBLIC_COMPONENTS_KIT_KEY=your_api_key_here
# For Vite
VITE_COMPONENTS_KIT_URL=https://api.componentskit.com
VITE_COMPONENTS_KIT_KEY=your_api_key_here3. Load Styles
Next.js App Router
// app/layout.tsx
const BASE_URL = process.env.NEXT_PUBLIC_COMPONENTS_KIT_URL;
const API_KEY = process.env.NEXT_PUBLIC_COMPONENTS_KIT_KEY;
const BUNDLE_URL = `${BASE_URL}/v1/public/bundle.css?key=${API_KEY}`;
const FONTS_URL = `${BASE_URL}/v1/public/fonts.txt?key=${API_KEY}`;
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<head>
<link href="https://fonts.googleapis.com" rel="preconnect" />
<link
crossOrigin="anonymous"
href="https://fonts.gstatic.com"
rel="preconnect"
/>
<link as="style" href={BUNDLE_URL} rel="preload" />
<link href={BUNDLE_URL} rel="stylesheet" />
<link href={FONTS_URL} rel="stylesheet" />
</head>
<body>{children}</body>
</html>
);
}Vite / React SPA
// App.tsx or main.tsx
import { useEffect } from "react";
const BASE_URL = import.meta.env.VITE_COMPONENTS_KIT_URL;
const API_KEY = import.meta.env.VITE_COMPONENTS_KIT_KEY;
const BUNDLE_URL = `${BASE_URL}/v1/public/bundle.css?key=${API_KEY}`;
const FONTS_URL = `${BASE_URL}/v1/public/fonts.txt?key=${API_KEY}`;
function App() {
useEffect(() => {
// Preload CSS bundle
const preload = document.createElement("link");
preload.rel = "preload";
preload.href = BUNDLE_URL;
preload.as = "style";
document.head.appendChild(preload);
// Load CSS bundle
const stylesheet = document.createElement("link");
stylesheet.rel = "stylesheet";
stylesheet.href = BUNDLE_URL;
document.head.appendChild(stylesheet);
// Load fonts
const fonts = document.createElement("link");
fonts.rel = "stylesheet";
fonts.href = FONTS_URL;
document.head.appendChild(fonts);
}, []);
return <>{/* your app */}</>;
}Core Concepts
Headless Components with Data Attributes
All components are unstyled and expose data-* attributes for CSS-based styling:
<Button variantName="primary" size="lg" isLoading>
Submit
</Button>Renders with these attributes for styling:
<button data-variant="primary" data-size="lg" data-loading="true">
Submit
</button>Polymorphic Components
Some components support the as prop to render as different HTML elements:
// Renders as <h2>
<Heading as="h2" variantName="section-title">Section</Heading>
// Renders as <span>
<Text as="span" variantName="caption">Inline text</Text>
// Renders as <a>
<Button as="a" href="/home" variantName="link">Go Home</Button>Polymorphic components: Button, Heading, Icon, Text
Composition with asChild
Components supporting asChild merge their props onto their child element:
import { Button } from "@components-kit/react";
import Link from "next/link";
// Button behavior with Link rendering
<Button asChild variantName="primary">
<Link href="/dashboard">Dashboard</Link>
</Button>;Components with asChild: Button, Badge
Components
| Component | Description | Optional Deps |
| ----------- | ------------------------------------------------------------------------ | ----------------------- |
| Alert | Contextual feedback messages with icon, heading, description, and action | - |
| Badge | Small status indicator for labels and counts | - |
| Button | Polymorphic button with loading, icons, and composition support | - |
| Checkbox | Boolean selection with indeterminate state support | - |
| Heading | Polymorphic heading (h1-h6) with semantic hierarchy | - |
| Icon | Flexible icon wrapper with consistent sizing | - |
| Input | Text input with type variants | - |
| RadioGroup | Radio button group with RadioGroupItem | - |
| Select | Dropdown with keyboard navigation and custom rendering | downshift |
| Separator | Visual divider (horizontal/vertical) | - |
| Skeleton | Loading placeholder with customizable dimensions | - |
| Slot | Utility for prop merging and asChild pattern | - |
| Switch | Binary toggle control | - |
| Table | Data table with sorting, pagination, selection, and expansion | @tanstack/react-table |
| Text | Polymorphic text element (p, span, strong, em, etc.) | - |
| Textarea | Multi-line text input with auto-resize | - |
Accessibility
All components follow WAI-ARIA guidelines:
- Semantic HTML - Proper elements and roles
- Keyboard Navigation - Full keyboard support (Tab, Enter, Space, Arrow keys)
- ARIA Attributes - Correct aria-* attributes for screen readers
- Focus Management - Visible focus indicators and logical focus order
Example accessibility features:
| Component | Accessibility Features |
| --------- | ------------------------------------------------- |
| Alert | role="alert", aria-live="polite" |
| Button | aria-disabled, aria-busy for loading |
| Checkbox | Label association, aria-invalid |
| Select | ARIA listbox pattern, type-ahead search |
| Table | aria-sort, aria-selected, keyboard navigation |
TypeScript
All components export their prop types:
import { Button, ButtonProps } from "@components-kit/react";
import type { ColumnDef } from "@components-kit/react"; // Re-exported from TanStack
// Extend props
interface MyButtonProps extends ButtonProps {
analyticsId: string;
}
// Generic components
import { Table } from "@components-kit/react";
interface User {
id: string;
name: string;
email: string;
}
<Table<User> data={users} columns={columns} />;Browser Support
- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
License
MIT License - see LICENSE for details.
