Installation
Scaffold a new rejoice app with a single command. The CLI will walk you through project name, router setup, default theme, and git initialization.
bunx create-rejoice-app@latest my-app
cd my-app
bun install
bun dev
Requires Bun installed. The scaffolder uses Bun as the default runtime and bundler.
CLI Flags
Every prompt can be skipped with a flag, making the CLI fully non-interactive for AI agents and CI:
bunx create-rejoice-app@latest my-app --router --theme dark --git
| Flag | Default | Description |
|---|---|---|
--router |
true |
Include React Router v6 |
--no-router |
— | Skip React Router |
--theme light|dark |
"light" |
Sets the initial theme for RejoiceProvider |
--git |
true |
Initialize a git repository |
--no-git |
— | Skip git init |
When all flags are provided along with the project name, no prompts are shown. Flags not provided will fall back to interactive prompts.
Quick Start
After scaffolding, your app is ready. Here's the entry point the CLI generates:
import { createRoot, RejoiceProvider } from "rejoice-js";
import App from "./App";
createRoot(document.getElementById("root")!).render(
<RejoiceProvider defaultTheme="light">
<App />
</RejoiceProvider>
);
Everything is imported from rejoice-js — React, components, hooks,
styling, and state management. No second import source needed.
import {
useState,
Button,
Card,
styled,
useTheme,
} from "rejoice-js";
const Wrapper = styled.div`
padding: ${({ theme }) => theme.spacing(3)};
background: ${({ theme }) => theme.colors.background};
`;
export default function App() {
const [count, setCount] = useState(0);
const { isDarkMode, toggleTheme } = useTheme();
return (
<Wrapper>
<Card title="Hello, rejoice">
<Button onClick={() => setCount(c => c + 1)}>
Clicked {count} times
</Button>
<Button onClick={toggleTheme}>
{isDarkMode ? "Light" : "Dark"} Mode
</Button>
</Card>
</Wrapper>
);
}
Project Structure
The scaffolded app follows a clean, minimal layout:
my-app/
index.html # Bun HTML entry point
package.json
tsconfig.json # jsxImportSource: "rejoice-js"
src/
main.tsx # App bootstrap with RejoiceProvider
App.tsx # Root component
App.styles.ts # styled-components
styled.d.ts # Theme type augmentation
store/
appStore.ts # Zustand store example
router.tsx # React Router config (if opted in)
pages/ # Route pages (if opted in)
The tsconfig.json sets jsxImportSource: "rejoice-js", so
JSX works without importing React. The library delegates to
react/jsx-runtime internally.
RejoiceProvider
The root provider that wires up Ant Design theming, styled-components theme context, and the Zustand theme store. Wrap your app with this once.
import { createRoot, RejoiceProvider } from "rejoice-js";
createRoot(document.getElementById("root")!).render(
<RejoiceProvider defaultTheme="dark">
<App />
</RejoiceProvider>
);
Props
| Prop | Type | Default | Description |
|---|---|---|---|
children |
React.ReactNode |
Required | Your application tree |
defaultTheme |
"light" | "dark" |
"light" |
Initial theme mode if no persisted preference exists |
What it does
-
Wraps your app with Ant Design's
ConfigProvider— switching betweendefaultAlgorithmanddarkAlgorithmbased on theme mode -
Wraps with styled-components
ThemeProvider— injecting theme tokens into all styled components -
Syncs with the Zustand theme store — so
useTheme()anduseThemeStore()work anywhere in the tree
Theme System
Rejoice ships a unified theme system that synchronizes Ant Design, styled-components,
and Zustand. Theme preference is automatically persisted to
localStorage under the key rejoice-theme-storage.
ConfigProviderThemeProvider
themeStoreuseTheme
The primary hook for reading and controlling the theme. Returns the current mode and actions to change it.
import { useTheme, Button, Switch } from "rejoice-js";
function ThemeToggle() {
const { mode, isDarkMode, toggleTheme, setTheme } = useTheme();
return (
<div>
<p>Current: {mode}</p>
<Switch
checked={isDarkMode}
onChange={toggleTheme}
/>
<Button onClick={() => setTheme("dark")}>
Force Dark
</Button>
</div>
);
}
Return value
| Property | Type | Description |
|---|---|---|
mode |
"light" | "dark" |
Current theme mode |
isDarkMode |
boolean |
Convenience boolean — true when dark |
toggleTheme |
() => void |
Flips between light and dark |
setTheme |
(mode: ThemeMode) => void |
Sets a specific theme mode |
useThemeStore
Direct access to the underlying Zustand store. Useful for selecting specific slices or subscribing outside React.
import { useThemeStore } from "rejoice-js";
// Select only what you need
const mode = useThemeStore((s) => s.mode);
const toggle = useThemeStore((s) => s.toggleTheme);
// Subscribe outside React
useThemeStore.subscribe((state) => {
console.log("Theme changed:", state.mode);
});
The store uses Zustand's persist middleware. Theme preference survives
page reloads automatically.
Theme Tokens
The styled-components theme object injected by RejoiceProvider. Access
these in any styled component via props.theme.
{
mode: "light" | "dark",
isDark: boolean,
colors: {
background: "#ffffff" | "#141414",
surface: "#f5f5f5" | "#1f1f1f",
text: "rgba(0,0,0,0.88)" | "rgba(255,255,255,0.85)",
primary: "#1677ff",
border: "#d9d9d9" | "#303030",
},
spacing: (n: number) => string // returns `${n * 8}px`
}
Usage in styled-components
import { styled } from "rejoice-js";
const Panel = styled.div`
background: ${({ theme }) => theme.colors.surface};
padding: ${({ theme }) => theme.spacing(2)};
border: 1px solid ${({ theme }) => theme.colors.border};
color: ${({ theme }) => theme.colors.text};
border-radius: 8px;
`;
Type augmentation
The scaffolded app includes src/styled.d.ts to give you full autocomplete
on theme tokens:
import "styled-components";
declare module "styled-components" {
export interface DefaultTheme {
mode: "light" | "dark";
isDark: boolean;
colors: {
background: string;
surface: string;
text: string;
primary: string;
border: string;
};
spacing: (n: number) => string;
}
}
Hooks
All standard React hooks are re-exported from rejoice-js so you never
need to import from react directly.
useState
State management
useEffect
Side effects
useLayoutEffect
Synchronous effects
useReducer
Complex state logic
useRef
Mutable references
useContext
Context consumption
useMemo
Memoized values
useCallback
Memoized callbacks
useId
Unique IDs
useTransition
Non-blocking updates
useDeferredValue
Deferred rendering
useSyncExternalStore
External store sync
// All from one import
import {
useState,
useEffect,
useRef,
useMemo,
useCallback,
} from "rejoice-js";
Utilities
React utilities and component helpers available from the same import.
memo
Component memoization
lazy
Code splitting
Suspense
Async boundaries
StrictMode
Development checks
Fragment
Invisible wrapper
createElement
JSX alternative
createContext
Context creation
forwardRef
Ref forwarding
React DOM
DOM rendering methods — use createRoot for your app entry point.
createRoot
Mount React app to DOM
hydrateRoot
Hydrate server-rendered HTML
JSX Runtime
Rejoice provides its own JSX runtime that delegates to React's. This enables
zero-config JSX — no import React from "react" needed anywhere.
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "rejoice-js"
}
}
With this config, TypeScript and Bun automatically resolve JSX transforms from
rejoice-js/jsx-runtime. You write JSX as usual and it just works.
Components
39+ Ant Design 5 components are pre-exported. They're automatically themed by
RejoiceProvider — dark mode, primary color, and all token overrides apply
with zero configuration.
Data Entry
Button
Actions & triggers
Input
Text input
Select
Dropdown selection
Form
Form wrapper & validation
DatePicker
Date selection
Upload
File uploads
Slider
Range input
Switch
Toggle boolean
Checkbox
Multi-select
Radio
Single-select
Data Display
Table
Tabular data
Card
Content container
Tabs
Tabbed content
Badge
Status indicator
Tag
Labels & tags
Tooltip
Hover info
Typography
Text & headings
Avatar
User avatar
List
List layout
Progress
Progress indicators
Overlay
Modal
Dialog windows
Drawer
Side panels
Dropdown
Contextual menus
Navigation
Menu
Navigation menus
Breadcrumb
Page hierarchy
Steps
Step-by-step flow
import { Button, Card, Table, Modal, Form, Input } from "rejoice-js";
// Use exactly like Ant Design — same props, same API.
// Theme is automatically applied by RejoiceProvider.
Layout & Grid
Ant Design's layout primitives for building page structure.
Layout
Page structure (Header, Sider, Content, Footer)
Space
Inline spacing
Row
Flex row
Col
Grid column
Divider
Content separator
Feedback & Status
Components for communicating state and results to users.
Spin
Loading spinner
Alert
Status messages
Result
Operation outcomes
Empty
Empty state placeholder
Skeleton
Loading placeholder
ConfigProvider
Global config overrides
Ant Design Theme
The Ant Design theme algorithms are available as antdTheme for advanced
use cases.
import { antdTheme, ConfigProvider } from "rejoice-js";
// Access Ant Design's theme algorithms
const { defaultAlgorithm, darkAlgorithm } = antdTheme;
// Override locally if needed
<ConfigProvider theme={{ algorithm: darkAlgorithm }}>
<MySection />
</ConfigProvider>
API
styled-components v6 is re-exported for CSS-in-JS with full theme token access.
styled
Create themed components
css
CSS helper for interpolation
keyframes
Define animations
createGlobalStyle
Global CSS injection
import { styled, css, keyframes, createGlobalStyle } from "rejoice-js";
const fadeIn = keyframes`
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
`;
const Card = styled.div`
background: ${({ theme }) => theme.colors.surface};
padding: ${({ theme }) => theme.spacing(3)};
border-radius: 12px;
animation: ${fadeIn} 0.3s ease;
`;
const GlobalStyle = createGlobalStyle`
body {
background: ${({ theme }) => theme.colors.background};
color: ${({ theme }) => theme.colors.text};
}
`;
Theming
All styled components inside RejoiceProvider automatically receive the
theme object. Use it for dark-mode-aware styling without any additional setup.
import { styled } from "rejoice-js";
const Header = styled.header`
background: ${({ theme }) =>
theme.isDark ? "rgba(255,255,255,0.04)" : "rgba(0,0,0,0.02)"};
border-bottom: 1px solid ${({ theme }) => theme.colors.border};
padding: ${({ theme }) => theme.spacing(2)} ${({ theme }) => theme.spacing(3)};
`;
// theme.isDark is a boolean — use it for conditional styles
// theme.spacing(n) returns `${n * 8}px` — use it for consistent spacing
Store API
Zustand v4 is re-exported for lightweight state management. Create stores with zero boilerplate.
create
Create a React-bound store
createStore
Create a vanilla store
useShallow
Shallow equality selector
import { create } from "rejoice-js";
interface CounterState {
count: number;
increment: () => void;
decrement: () => void;
}
export const useCounter = create<CounterState>((set, get) => ({
count: 0,
increment: () => set({ count: get().count + 1 }),
decrement: () => set({ count: get().count - 1 }),
}));
import { useShallow } from "rejoice-js";
import { useCounter } from "./store/counterStore";
// useShallow prevents re-renders when unrelated state changes
const { count, increment } = useCounter(
useShallow((s) => ({ count: s.count, increment: s.increment }))
);
Middleware
Three Zustand middleware functions are pre-exported for common patterns.
persist
Persist state to localStorage
devtools
Redux DevTools integration
subscribeWithSelector
Fine-grained subscriptions
import { create, persist, devtools } from "rejoice-js";
interface Settings {
language: string;
notifications: boolean;
setLanguage: (lang: string) => void;
toggleNotifications: () => void;
}
export const useSettings = create<Settings>()(
devtools(
persist(
(set, get) => ({
language: "en",
notifications: true,
setLanguage: (lang) => set({ language: lang }),
toggleNotifications: () =>
set({ notifications: !get().notifications }),
}),
{ name: "settings-storage" }
)
)
);
Type Exports
TypeScript types exported for use in your application code.
import type {
ThemeMode,
ThemeState,
RejoiceProviderProps,
DefaultTheme,
} from "rejoice-js";
| Type | Definition | Description |
|---|---|---|
ThemeMode |
"light" | "dark" |
Union type for theme modes |
ThemeState |
{ mode, isDarkMode, toggleTheme, setTheme } |
Shape of the theme store |
RejoiceProviderProps |
{ children, defaultTheme? } |
Props for RejoiceProvider |
DefaultTheme |
styled-components theme interface | Re-exported from styled-components for type augmentation |