Open-code foundations
Add and inspect a Button
Generate the first component, render its variants, and read the source and dependencies before treating the output as a black box.
The add command resolves a registry item, installs missing dependencies, and writes the component files into your project. You get source files on disk, not a black-box import.
Use the CLI view command before add when you want to inspect the resolved official item without writing it. After adding Button, review both the source diff and package diff. Notice how native button props are forwarded, how variants become classes, and how the class-merging helper is used. The exact code depends on the selected base and style, so reading your file is more useful than memorizing one screenshot.
npx shadcn@latest add button
When the command finishes, confirm the file landed where components.json says it should:
ls components/ui/button.tsx
You should see components/ui/button.tsx (or the path your aliases define). If the file is missing, check the CLI output for a failed dependency install.
A variant is a semantic promise, not merely a color. Destructive should identify a consequential action. Disabled must prevent interaction and expose state. A pending button needs text or another accessible indication beyond a spinner. Inspect the final DOM. The result should still be a real <button> unless navigation semantics require a link.
Render the default, secondary, outline, and destructive variants plus disabled and pending examples on one page. Activate each real button with Enter and Space. Inspect focus rings and accessible names in DevTools. Note every new dependency the command added to package.json.
Try this on your own project: add Button, render four variants, and keyboard-test each one before you move on to Card. Write down the primitive import you found in the source file.
Lesson completed