Skip to content

Quickstart

Render your first Cynosure components in under five minutes.

A minimal end-to-end Cynosure app.

Terminal window
npm install @arshad-shah/cynosure-react @arshad-shah/cynosure-tokens

Prefer automation? The CLI detects your framework, writes the CSS import, and wires up the provider:

Terminal window
npx @arshad-shah/cynosure-cli init

ThemeProvider owns the theme state and toggles data-theme on <html>. TooltipProvider deduplicates the shared overlay-positioning context so nested tooltips don’t double-mount listeners. DirectionProvider lets you render in RTL without re-mounting the tree.

src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import {
DirectionProvider,
ThemeProvider,
TooltipProvider,
} from '@arshad-shah/cynosure-react';
import '@arshad-shah/cynosure-tokens/css';
import '@arshad-shah/cynosure-tokens/css/dark';
import '@arshad-shah/cynosure-react/styles.css';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<ThemeProvider defaultTheme="system">
<DirectionProvider dir="ltr">
<TooltipProvider>
<App />
</TooltipProvider>
</DirectionProvider>
</ThemeProvider>
</React.StrictMode>,
);

The simplest Cynosure component is Button:

src/App.tsx
import { Button } from '@arshad-shah/cynosure-react';
export default function App() {
return (
<Button onClick={() => alert('Hello, Cynosure!')}>
Click me
</Button>
);
}
src/App.tsx
import {
Button,
Card,
CardContent,
CardHeader,
Heading,
Stack,
Text,
} from '@arshad-shah/cynosure-react';
export default function App() {
return (
<Stack gap="6" padding="6" maxWidth="md" marginX="auto">
<Heading level={1}>Hello, Cynosure</Heading>
<Card>
<CardHeader>
<Heading level={2} size="lg">
A minimal card
</Heading>
</CardHeader>
<CardContent>
<Stack gap="3">
<Text>
Cynosure ships primitives that render real HTML and components
that compose those primitives.
</Text>
<Button>Primary action</Button>
</Stack>
</CardContent>
</Card>
</Stack>
);
}
import { useTheme } from '@arshad-shah/cynosure-react';
function ThemeSwitcher() {
const { theme, setTheme, themes } = useTheme();
return (
<select value={theme} onChange={(e) => setTheme(e.target.value)}>
{themes.map((t) => (
<option key={t} value={t}>{t}</option>
))}
</select>
);
}
import {
Button,
Form,
FormControl,
FormField,
FormLabel,
FormMessage,
Input,
Stack,
} from '@arshad-shah/cynosure-react';
export function ContactForm() {
return (
<Form onSubmit={(e) => { e.preventDefault(); /* … */ }}>
<Stack gap="4">
<FormField name="email" required>
<FormLabel>Email</FormLabel>
<FormControl>
<Input type="email" />
</FormControl>
<FormMessage />
</FormField>
<Button type="submit">Send</Button>
</Stack>
</Form>
);
}