# Resume

> Printable resume layout with experience, skills, and projects.

A shadcn/ui block from the [@atroui](https://www.atroui.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/atroui/resume).

- Page, with a live preview: https://shadcn.exchange/r/atroui/resume
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/atroui/resume-light-6cec4302c4bbb639.png
- Registry item: https://www.atroui.com/r/resume.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://www.atroui.com/r/resume.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `lucide-react`
- Registry items: `@atroui/utils`

## Files

### `registry/default/blocks/resume.tsx`

```tsx
import type { ReactNode } from "react"
import {
  Briefcase,
  Building2,
  Code2,
  GraduationCap,
  Mail,
  MapPin,
  Phone,
} from "lucide-react"

import { cn } from "@/lib/utils"

/** Edit this blob after install — printable via `.resume-print`. */
const CONTENT = {
  name: "Your Name",
  title: "Product engineer",
  summary:
    "Designer-engineer who ships calm interfaces and durable systems. Comfortable across product, frontend, and delivery.",
  email: "hello@example.com",
  phone: "+1 555 000 0000",
  location: "Remote",
  experience: [
    {
      role: "Founding Engineer",
      company: "Example Studio",
      period: "2024 — Present",
      description: [
        "Owned end-to-end product delivery for client MVPs.",
        "Built reusable UI systems and host-bound tools.",
      ],
    },
    {
      role: "Frontend Engineer",
      company: "Acme",
      period: "2022 — 2024",
      description: [
        "Shipped design-system primitives used across web apps.",
        "Improved Core Web Vitals and accessibility baselines.",
      ],
    },
  ],
  education: [
    {
      degree: "B.S. Computer Science",
      school: "State University",
      year: "2022",
    },
  ],
  skills: ["TypeScript", "React", "Next.js", "Design systems", "Product"],
  projects: [
    {
      title: "Personal site kit",
      description: "Narrow chrome and indie home sections for AtroUI.",
      href: "https://www.atroui.com",
    },
    {
      title: "Studio tools",
      description: "OG, scope, and thumbnail demos.",
      href: "https://www.atroui.com/docs",
    },
  ],
}

export function Resume({
  name = CONTENT.name,
  title = CONTENT.title,
  summary = CONTENT.summary,
  email = CONTENT.email,
  phone = CONTENT.phone,
  location = CONTENT.location,
  experience = CONTENT.experience,
  education = CONTENT.education,
  skills = CONTENT.skills,
  projects = CONTENT.projects,
  className,
}: {
  name?: string
  title?: string
  summary?: string
  email?: string
  phone?: string
  location?: string
  experience?: Array<{
    role: string
    company: string
    period: string
    description: string[]
  }>
  education?: Array<{ degree: string; school: string; year: string }>
  skills?: string[]
  projects?: Array<{ title: string; description: string; href?: string }>
  className?: string
} = {}) {
  return (
    <div
      className={cn(
        "resume-print overflow-hidden rounded-[10px] border border-border-subtle bg-background",
        className
      )}
    >
      <header className="border-b border-border-subtle bg-muted/40 p-6 sm:p-8">
        <div className="space-y-3">
          <div>
            <h2 className="text-[1.75rem] font-medium tracking-[-0.02em] text-foreground sm:text-[2rem]">
              {name}
            </h2>
            <p className="mt-1 text-[15px] text-muted-foreground">{title}</p>
          </div>
          <p className="max-w-[52ch] text-[14px] leading-[1.65] text-muted-foreground">
            {summary}
          </p>
          <div className="flex flex-wrap gap-2 pt-1">
            <MetaChip href={`mailto:${email}`} icon={Mail}>
              {email}
            </MetaChip>
            {phone ? (
              <MetaChip href={`tel:${phone.replace(/\s+/g, "")}`} icon={Phone}>
                {phone}
              </MetaChip>
            ) : null}
            <MetaChip icon={MapPin}>{location}</MetaChip>
          </div>
        </div>
      </header>

      <div className="grid grid-cols-1 lg:grid-cols-3">
        <div className="p-6 sm:p-8 lg:col-span-2">
          <section aria-labelledby="resume-experience">
            <SectionLabel id="resume-experience" icon={Briefcase}>
              Experience
            </SectionLabel>
            <div className="space-y-8 pl-2">
              {experience.map((job) => (
                <div
                  key={`${job.role}-${job.company}-${job.period}`}
                  className="relative pl-7"
                >
                  <span
                    aria-hidden
                    className="absolute top-1.5 left-0 h-2.5 w-2.5 rounded-full border-2 border-background bg-foreground"
                  />
                  <div className="flex flex-col gap-1 sm:flex-row sm:items-baseline sm:justify-between">
                    <h3 className="text-[15px] font-medium text-foreground">
                      {job.role}
                    </h3>
                    <span className="w-fit font-mono text-[11px] text-muted-foreground">
                      {job.period}
                    </span>
                  </div>
                  <div className="mt-1 flex items-center gap-1.5 text-[13px] text-muted-foreground">
                    <Building2 className="h-3.5 w-3.5" strokeWidth={1.75} />
                    {job.company}
                  </div>
                  <ul className="mt-3 space-y-1.5 text-[13.5px] leading-[1.6] text-muted-foreground">
                    {job.description.map((line) => (
                      <li key={line} className="flex gap-2.5">
                        <span
                          aria-hidden
                          className="mt-[8px] h-[3px] w-[3px] shrink-0 rounded-full bg-muted-foreground/50"
                        />
                        <span>{line}</span>
                      </li>
                    ))}
                  </ul>
                </div>
              ))}
            </div>
          </section>
        </div>

        <aside className="flex flex-col gap-8 border-t border-border-subtle bg-muted/30 p-6 sm:p-8 lg:border-t-0 lg:border-l">
          <section aria-labelledby="resume-education">
            <SectionLabel id="resume-education" icon={GraduationCap}>
              Education
            </SectionLabel>
            <div className="space-y-4">
              {education.map((ed) => (
                <div
                  key={`${ed.degree}-${ed.school}`}
                  className="border-l border-border-subtle pl-3"
                >
                  <h3 className="text-[14px] font-medium text-foreground">
                    {ed.degree}
                  </h3>
                  <p className="mt-0.5 text-[13px] text-muted-foreground">
                    {ed.school}
                  </p>
                  <p className="mt-1 font-mono text-[11px] text-muted-foreground">
                    {ed.year}
                  </p>
                </div>
              ))}
            </div>
          </section>

          <section aria-labelledby="resume-skills">
            <SectionLabel id="resume-skills" icon={Code2}>
              Skills
            </SectionLabel>
            <ul className="flex flex-wrap gap-1.5">
              {skills.map((skill) => (
                <li
                  key={skill}
                  className="rounded-[4px] border border-border-subtle bg-background px-2 py-1 font-mono text-[11px] text-muted-foreground"
                >
                  {skill}
                </li>
              ))}
            </ul>
          </section>
        </aside>

        {projects.length > 0 ? (
          <div className="border-t border-border-subtle p-6 sm:p-8 lg:col-span-3">
            <section aria-labelledby="resume-projects">
              <SectionLabel id="resume-projects" icon={Code2}>
                Selected work
              </SectionLabel>
              <ul className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3">
                {projects.map((project) => (
                  <li
                    key={project.title}
                    className="rounded-[8px] border border-border-subtle p-3.5"
                  >
                    {project.href ? (
                      <a
                        href={project.href}
                        target="_blank"
                        rel="noopener noreferrer"
                        className="text-[13.5px] font-medium text-foreground hover:underline"
                      >
                        {project.title}
                      </a>
                    ) : (
                      <h3 className="text-[13.5px] font-medium text-foreground">
                        {project.title}
                      </h3>
                    )}
                    <p className="mt-1.5 text-[12.5px] leading-[1.55] text-muted-foreground">
                      {project.description}
                    </p>
                  </li>
                ))}
              </ul>
            </section>
          </div>
        ) : null}
      </div>
    </div>
  )
}

function SectionLabel({
  id,
  icon: Icon,
  children,
}: {
  id: string
  icon: typeof Briefcase
  children: ReactNode
}) {
  return (
    <h3
      id={id}
      className="mb-4 flex items-center gap-2 font-mono text-[10.5px] tracking-[0.12em] text-muted-foreground uppercase"
    >
      <Icon className="h-3.5 w-3.5" strokeWidth={1.75} aria-hidden />
      {children}
    </h3>
  )
}

function MetaChip({
  href,
  icon: Icon,
  children,
}: {
  href?: string
  icon: typeof Mail
  children: ReactNode
}) {
  const className =
    "inline-flex items-center gap-1.5 rounded-lg border border-border-subtle bg-background px-2.5 py-1 font-mono text-[11px] text-muted-foreground"
  const inner = (
    <>
      <Icon className="h-3 w-3" strokeWidth={1.75} aria-hidden />
      {children}
    </>
  )
  if (href) {
    return (
      <a href={href} className={cn(className, "hover:text-foreground")}>
        {inner}
      </a>
    )
  }
  return <span className={className}>{inner}</span>
}
```
