Installation
How to add Cynosure to a Next.js, Vite, Remix, or CRA project.
Installation
Section titled “Installation”Zero-config
Section titled “Zero-config”npx @arshad-shah/cynosure-cli initpnpm dlx @arshad-shah/cynosure-cli inityarn dlx @arshad-shah/cynosure-cli initbunx @arshad-shah/cynosure-cli initDetects your framework (Next.js App Router, Next.js Pages, Vite, CRA, Remix),
prints the exact install command for your package manager, writes the single
CSS import, and wires up CynosureProvider (for the Next.js App Router it also
scaffolds a providers.tsx). Add --dry-run to preview.
Requirements
Section titled “Requirements”- Node 22 or newer for local development (Cynosure is authored against ESM and uses native TypeScript loading).
- React 18 or 19 (peer dependency). Works with Next.js 13 / 14 / 15, Vite, CRA, and Remix.
Manual install
Section titled “Manual install”npm install @arshad-shah/cynosure-react @arshad-shah/cynosure-tokenspnpm add @arshad-shah/cynosure-react @arshad-shah/cynosure-tokensyarn add @arshad-shah/cynosure-react @arshad-shah/cynosure-tokensbun add @arshad-shah/cynosure-react @arshad-shah/cynosure-tokensImport the CSS — the one-line way
Section titled “Import the CSS — the one-line way”import '@arshad-shah/cynosure-react/all.css';This single file bundles tokens (light + dark) and every component’s CSS. For most apps it’s the right choice.
Webfonts (optional)
Section titled “Webfonts (optional)”The default token font stacks resolve to Geist Variable (sans) and JetBrains Mono Variable (mono), falling through to system fonts when those families aren’t loaded. Add one more import to bundle them:
import '@arshad-shah/cynosure-react/fonts.css';Kept separate from all.css so you don’t pay the ~400 KB woff2 cost if you
have your own font pipeline (next/font, self-hosted, CDN). With next/font,
skip this import and override --cynosure-font-family-sans / -mono with
your font’s CSS variable.
The three-import way (granular control)
Section titled “The three-import way (granular control)”If you want to load tokens and component styles separately — useful when you want to inline critical CSS, ship dark overrides conditionally, or control cascade order yourself:
import '@arshad-shah/cynosure-tokens/css'; // design tokens, light themeimport '@arshad-shah/cynosure-tokens/css/dark'; // dark overrides (optional)import '@arshad-shah/cynosure-react/styles.css'; // component styles barrelPer-component CSS
Section titled “Per-component CSS”If you import per-component, your bundler wires up the CSS automatically:
import { Button } from '@arshad-shah/cynosure-react/button';Every per-component JS entry prepends its CSS imports, so subpath imports
never need a manual stylesheet include. Each component imports core.css
(the universal scaffolding — the layout-prop @property declarations and
the body reset) followed by only the shared chunks under shared/ that it
participates in, then its own rules. Shared rules are split by which
components use them, so a single-component import pulls just that
component’s CSS (~1.5–3 kB brotli) rather than the whole shared baseline —
and importing many components still deduplicates each chunk to one copy.
If you’re code-splitting and want to preload the universal scaffolding yourself, it’s reachable directly:
import '@arshad-shah/cynosure-react/core.css';Wrap your app
Section titled “Wrap your app”CynosureProvider composes ThemeProvider, DirectionProvider, LocaleProvider, and the global TooltipProvider in a single wrapper:
import { CynosureProvider } from '@arshad-shah/cynosure-react';
<CynosureProvider theme={{ defaultTheme: 'system' }}> <App /></CynosureProvider>Everything is optional — pass only what you want to override. The individual providers are still exported if you prefer to compose them yourself.
Framework-specific setup
Section titled “Framework-specific setup”Next.js App Router
Section titled “Next.js App Router”Create a providers.tsx client boundary to wrap the server root layout:
'use client';import { CynosureProvider } from '@arshad-shah/cynosure-react';
export function Providers({ children }: { children: React.ReactNode }) { return <CynosureProvider>{children}</CynosureProvider>;}import '@arshad-shah/cynosure-react/all.css';import { Providers } from './providers';
export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en" suppressHydrationWarning> <body> <Providers>{children}</Providers> </body> </html> );}Next.js Pages Router
Section titled “Next.js Pages Router”import '@arshad-shah/cynosure-react/all.css';import type { AppProps } from 'next/app';import { CynosureProvider } from '@arshad-shah/cynosure-react';
export default function MyApp({ Component, pageProps }: AppProps) { return ( <CynosureProvider> <Component {...pageProps} /> </CynosureProvider> );}import '@arshad-shah/cynosure-tokens/css';import '@arshad-shah/cynosure-tokens/css/dark';import '@arshad-shah/cynosure-react/styles.css';import React from 'react';import ReactDOM from 'react-dom/client';import { CynosureProvider } from '@arshad-shah/cynosure-react';import App from './App';
ReactDOM.createRoot(document.getElementById('root')!).render( <React.StrictMode> <CynosureProvider> <App /> </CynosureProvider> </React.StrictMode>,);import '@arshad-shah/cynosure-react/all.css';import { CynosureProvider } from '@arshad-shah/cynosure-react';import { Outlet } from '@remix-run/react';
export default function App() { return ( <CynosureProvider> <Outlet /> </CynosureProvider> );}Create React App
Section titled “Create React App”import '@arshad-shah/cynosure-react/all.css';import React from 'react';import ReactDOM from 'react-dom/client';import { CynosureProvider } from '@arshad-shah/cynosure-react';import App from './App';
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( <React.StrictMode> <CynosureProvider> <App /> </CynosureProvider> </React.StrictMode>,);Optional themes
Section titled “Optional themes”import '@arshad-shah/cynosure-themes/terminal';import '@arshad-shah/cynosure-themes/high-contrast';TypeScript
Section titled “TypeScript”Cynosure is authored in TypeScript and publishes types with full JSDoc. If you
use skipLibCheck: false, make sure your lib includes DOM and DOM.Iterable.
Peer dependencies
Section titled “Peer dependencies”| Peer | Range | Required |
|---|---|---|
react | >=18 | yes |
react-dom | >=18 | yes |
react-hook-form | ^7 | only if you import @arshad-shah/cynosure-react/rhf |
See the Quickstart for a minimal end-to-end example, or the RSC guide for Next.js App Router integration.