
Every new React app starts with the same wiring — generating a Tailwind dashboard base instead
routing, theme, dark mode, app shell, data table, auth stubs, permissions, form validation, mock data.
It's identical across projects and none of it is the product.
The alternative is to generate that base and start from there.
npx dashforge-cli my-app --lib tw --template dashboard
What's in the generated project:
- Vite 7, React Router 8 (framework mode), TypeScript
- app shell with nav, workspace switcher, stat cards, data table, users CRUD
- mock auth with three roles (admin / editor / viewer)
- component-level RBAC - a viewer doesn't get a disabled button, they don't get the button
- forms with validation
- public routes pre-rendered to static HTML, everything behind auth stays CSR
- dark mode already wired
On the Tailwind side:
The UI layer is token-first. tailwind.config.ts loads a preset, and utilities like bg-primary-600 resolve to CSS variables driven by a theme object, so rebranding is one 50->900 ramp, not a find-and-replace across components:
color: { ...defaultTWThemeLight.color, primary: brandPrimary }
Dark mode swaps the entire token set instead of toggling per-component classes, so the brand color survives the switch.
The theme allso carries component defaults, the layer Tailwind normally leaves to you:
const components = {
TextField: { defaults: { size: 'md', fullWidth: true } },
Stack: { defaults: { gap: 4 } },
Box: { defaults: { variant: 'outlined', rounded: 'lg' } },
};
Set once, every instance inherits its; a prop on the element still wins.
<Card variant="outlined" rounded="lg" p={0}>
<CardContent p={4}> <Stack gap={2}>
<Typography variant="body2" color="muted">{label}</Typography>
<Typography variant="h4">{value}</Typography> </Stack> </CardContent> </Card>
Layout stays plain Tailwind, grid grid-cols-1 gap-4 lg:grid-cols-4 in the page, props inside the components.
Where your own code starts:
The API layer ships with a mock/live switch. The app runs standalone against mock data, and you swap a single odulle once the backend exists. So after npm run dev the app is already up, and the work left is replacing mock resources with real ones and adding domain routes. Not rebuilding the shell.
--lib tw generates the Tailwind track. No arguments runs interactive mode; -- no-install if you want to read the output before installing anything
Open source: https://github.com/kensaadi/dashforge-cli