Installation
A CLI copies components into your repo and brings whatever they depend on. Nothing is generated, nothing is hidden, and there is no package wrapping the code you end up with.
Quick start
npm i -D astralyx-ui npx astralyx-ui init npx astralyx-ui add button
init writes a components.json, drops in the two helpers every component needs, and installs the theme. add copies a component and everything it imports.
Wire up the theme
init writes the token layer to src/styles/astralyx.css. Import it from your Tailwind entry:
@import 'tailwindcss'; @import './styles/astralyx.css';
That file carries the colour tokens, the surface ladder and the keyframes components animate with. Without it everything renders unstyled.
Adding components
Dependencies come along without being asked. data-grid pulls table, checkbox and empty; anything needing an npm package gets it installed.
npx astralyx-ui add data-grid dialog toast # several at once npx astralyx-ui add --all # every component npx astralyx-ui list # the catalogue, by category npx astralyx-ui info data-grid # what it would bring with it npx astralyx-ui add button --dry-run # look before you leap
add skips anything that already exists and says so. Once you have edited a component it is yours — pass --overwrite only when you actually mean to lose those changes.Where things go
components.json holds both the folders files are written to and the aliases their imports use, so you can keep components anywhere and the imports follow.
{
"tsx": true,
"tailwind": { "css": "src/index.css" },
"aliases": {
"ui": "@/components/ui",
"primitives": "@/components/primitives",
"lib": "@/lib"
},
"paths": {
"ui": "src/components/ui",
"primitives": "src/components/primitives",
"lib": "src/lib",
"styles": "src/styles"
}
}Your bundler needs to resolve whatever alias you choose. For Vite and TypeScript that is one entry each:
import { fileURLToPath, URL } from 'node:url'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [react(), tailwindcss()],
resolve: {
alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) },
},
})What gets installed
The CLI itself has no runtime dependencies. These are what the components need, and only the ones you actually use are added:
| Package | Needed by |
|---|---|
| cn | Every component. Backs the cn() helper that resolves conflicting Tailwind classes by argument order. |
| class-variance-authority | Anything with variants — buttons, badges, inputs. |
| lucide-react | Anything with an icon. |
| shiki | CodeBlock, QueryEditor and the other highlighted surfaces. |
| react-hook-form | Form only. |
Then use it
import { Button } from '@/components/ui/button'
<Button color="blue" size="lg">Deploy</Button>The file is in your repo now. Edit it, rename it, delete half of it — nothing upstream will argue.