Build your portfolio
A ten-minute walkthrough: install a template, theme it, swap in your content, add a project gallery and deploy.
This guide takes you from an empty folder to a deployed portfolio. It uses Vite; in Next.js or React Router the steps are the same apart from where you render the page (see the note in step 2).
1. Create the app
npx shadcn@latest init --template vite --name my-portfolio
cd my-portfolioThis creates a Vite + React + TypeScript app with Tailwind CSS v4, the @/ import alias and components.json already set up. When it asks for a component library, any choice works: Base UI and Radix are both supported. Adding the kit to an existing app instead? Follow the shadcn/ui installation guide for your framework first (it needs Tailwind CSS v4 and the @/ alias), then run npx shadcn@latest init.
Then add the kit's registry to components.json:
{
"registries": {
"@portfolio-kit": "https://www.parthjadhav.com/products/portfolio-kit/r/{name}.json"
}
}2. Pick a template and install it
Browse the templates and pick the one closest to what you do. There are templates for developers, designers, writers, photographers and freelancers, plus a résumé, a link-in-bio page and a 404. This guide uses the Developer template:
npx shadcn@latest add @portfolio-kit/template-developerThe CLI adds the template as src/components/template-developer.tsx (Vite projects alias @/ to src/), plus every kit component it uses (in src/components/portfolio/), the hooks and helpers they need, and the kit's base tokens. Render it as your page, in src/App.tsx:
import TemplateDeveloper from "@/components/template-developer"
export default function App() {
return <TemplateDeveloper />
}Run npm run dev. You should see the full template with its sample content.
In Next.js, render the template from
app/page.tsx. Kit components use hooks, so add"use client"at the top of the template file (and of any kit component your bundler complains about).
3. Make it look like you
Open the theme builder. Choose a starting point (Editorial for a serif look, Swiss for strict type, Terminal for mono everything…), then adjust the accent, neutrals, fonts, radius and shadows. The whole site, previews included, switches to your theme as you go. Use Shuffle to explore and Undo (⌘Z) to step back.
When you're happy, copy the CSS tab and replace the :root and .dark blocks in src/index.css with it. Install the font packages the builder lists and add its import lines. Or download theme.json and run npx shadcn@latest add ./theme.json. See Theming for what each token does.
4. Swap in your content
Open src/components/template-developer.tsx. Everything the page says lives in one content object at the top of the file: your name, role, links, experience, projects and writing.
const content: DeveloperContent = {
name: "Your Name",
role: "Senior engineer",
tagline: "One sentence about the work you do and who it's for.",
email: "you@example.com",
// …experience, projects, open source, writing
}The object is typed, so your editor tells you what each field expects. Delete entries you don't need; sections without content can be removed from the JSX below. Put your images in public/ and reference them as /lumen.jpg.
5. Add a component
Say you want a card linking to one project, and a gallery for its page that you can click through. Install the two components:
npx shadcn@latest add @portfolio-kit/project-card @portfolio-kit/lightboximport { Lightbox, LightboxTrigger } from "@/components/portfolio/lightbox"
import {
ProjectCard,
ProjectCardContent,
ProjectCardDescription,
ProjectCardMedia,
ProjectCardTitle,
} from "@/components/portfolio/project-card"
export function LumenCard() {
return (
<ProjectCard href="/work/lumen">
<ProjectCardMedia>
<img src="/lumen/cover.jpg" alt="" />
</ProjectCardMedia>
<ProjectCardContent>
<ProjectCardTitle>Lumen</ProjectCardTitle>
<ProjectCardDescription>
A design system for eleven products.
</ProjectCardDescription>
</ProjectCardContent>
</ProjectCard>
)
}
export function LumenGallery() {
return (
<Lightbox label="Lumen" className="grid grid-cols-2 gap-4">
<LightboxTrigger
src="/lumen/dashboard.jpg"
alt="The Lumen dashboard"
className="col-span-2 aspect-video"
/>
<LightboxTrigger src="/lumen/tokens.jpg" alt="Token pipeline" className="aspect-square" />
<LightboxTrigger src="/lumen/mobile.jpg" alt="Lumen on a phone" className="aspect-square" />
</Lightbox>
)
}Save this as src/components/lumen.tsx, then render <LumenCard /> in your work section and <LumenGallery /> on the project's page. Every component page shows more examples to copy, and its API section lists every prop. Components you install follow your theme automatically.
6. Check it
- Toggle dark mode and look at every section.
- Resize to phone width (390px): nothing should scroll sideways.
- Tab through the page: every link and button shows a focus ring.
- Turn on "reduce motion" in your OS settings: entrance effects are skipped and content shows at once.
- Print the page (or save as PDF): content hidden by scroll effects prints fully, and the résumé template lays out on A4 or Letter.
7. Deploy
npm run buildVite writes a static site to dist/. Upload it to any static host: Netlify, Cloudflare Pages, Vercel or GitHub Pages. For GitHub Pages under /<repo>/, set base: "/<repo>/" in vite.config.ts. In Next.js, deploy the project as usual.
That's it. From here, browse the components for sections to add, or read Customization to change the markup.