Generate a CV From Your Website
Most people maintain a portfolio and a CV as two separate documents. That is how names, dates, and job titles slowly drift apart.
Your website should hold the source material. A CV is a print-focused view of the same information. It needs different spacing and less ornament, but it should not need a second round of maintenance every time something changes.
Share the facts, not every layout choice
Start with an About or Resume page that contains the facts a reader needs: your name, role, contact details, experience, education, projects, and a few relevant skills. Keep those details in the same data files or content collection that power the website.
The screen version can invite exploration. The printed version should be fast to scan. Hide navigation, tighten vertical space, remove decorative images, and keep each experience entry together. That is enough for most portfolios.
Here is a small React component using Tailwind. The same idea works in Astro, Vue, plain HTML, or any framework that can emit CSS for print.
export default function Resume() {
return (
<main className="mx-auto max-w-3xl p-6 print:max-w-none print:p-0">
<header className="border-b border-slate-200 pb-6 print:pb-4">
<h1 className="text-4xl font-bold print:text-2xl">Jane Developer</h1>
<p className="mt-1 text-slate-600">
Product engineer building tools for customer teams.
</p>
<p className="mt-3 text-sm">jane@example.com · janedeveloper.com</p>
<nav className="mt-4 print:hidden" aria-label="Page navigation">
<a href="#work">Work</a>
<a className="ml-4" href="#projects">Projects</a>
</nav>
</header>
<section id="work" className="mt-8 break-inside-avoid print:mt-5">
<h2 className="text-xl font-semibold">Experience</h2>
<article className="mt-3">
<div className="flex flex-wrap justify-between gap-x-4">
<h3 className="font-medium">Senior developer, Example Co.</h3>
<p className="text-sm text-slate-600">2020 to present</p>
</div>
<p className="mt-1">
Built and maintained the product teams use to manage customer work.
</p>
</article>
</section>
<section id="projects" className="mt-8 break-inside-avoid print:mt-5">
<h2 className="text-xl font-semibold">Selected project</h2>
<p className="mt-3">
An open-source tool that turns structured portfolio data into a
printable CV.
</p>
</section>
</main>
);
}
Add a print layer with restraint
Tailwind includes a print variant, so print:hidden, print:p-0, and print:text-2xl work without creating a custom print breakpoint. The important class in the example is break-inside-avoid. It asks the browser to keep a short section together instead of slicing it in half at a page boundary.
Do not try to recreate an A4 sheet with a magic width class. Let the print dialog control paper size and margins. Check the page in both A4 and Letter preview if you expect an international audience, then adjust content before shrinking type. A CV with a sensible second page is better than one packed too tightly to read.
Export deliberately
For a personal site, the browser’s print dialog is usually the best PDF generator. It makes page breaks, margins, and font fallbacks visible before you send the file to someone.
Automate PDF creation only when it is part of a release process. In that case, build and serve the site first, then point a browser automation tool at the real resume route. Puppeteer’s Page.pdf() uses print CSS by default, which means the same print: rules still apply.
Update an experience entry once, inspect the print preview, and the website and PDF reflect the same data.