To turn a Figma design into a Next.js component library, move the design's colours, type and spacing into design tokens first, then build small primitives such as buttons and headings, compose those into page sections like heroes and feature grids, and assemble pages from the sections. Type every component's props in TypeScript and decide the responsive behaviour the Figma file does not show. The result is a library a team builds new pages from, rather than a set of one-off pages.
This is the approach I take for Next.js and React websites: server-rendered pages on TypeScript and Tailwind CSS, built from a shared, typed component library, so a new landing page is a matter of composing tested sections rather than starting from a blank canvas.
Why build a component library instead of pages?
Because the second page should be cheaper than the first. If you build page by page, every new campaign page is a fresh build, and small differences in spacing and type creep in. With a library, a new page is a list of sections and some content.
It also protects consistency. When every page uses the same typed components, a campaign page or an event page cannot quietly drift away from the brand. Fixing a bug in the hero fixes it on every page that uses the hero. And a one-off event or summit page can live on the main codebase instead of a separate microsite, which keeps its traffic and links on your own domain.
How do Figma concepts map to code?
| In Figma | In the Next.js codebase |
|---|---|
| Colour and text styles | Design tokens in the Tailwind theme |
| Spacing and layout grid | Spacing scale and container components |
| Components and variants | React components with typed variant props |
| Auto layout | Flexbox and grid utilities |
| Frames for desktop and mobile | Responsive classes at agreed breakpoints |
| A page design | A list of sections with content |
The mapping is rarely one to one. Figma variants often include states that code handles on its own, such as hover and focus, and the layout grid usually becomes a container component plus the spacing scale rather than anything literal.
What order should you build in?
Tokens. Brand colours, font families, the type scale, spacing and radii go into the Tailwind theme before any component exists. If a value is not a token, it does not ship.
Primitives. Buttons, headings, text, containers, cards and form fields. Each has a small set of variants that match the Figma component's variants, and nothing else.
Sections. Hero, logo strip, feature grid, testimonial, pricing, FAQ, call to action. These are the units marketers think in, and the units pages are built from.
Pages. A route that lists sections in order and passes them content. Routine pages need no new CSS at all.
Why type the props?
Because a component library is shared, and shared code needs guardrails. In TypeScript, a section that takes the wrong props fails at build time rather than in production. If a hero requires a heading and accepts one of three background styles, the compiler enforces that on every page that uses it. A minimal hero might look like this:
type HeroProps = {
heading: string;
subheading?: string;
background: "light" | "dark" | "brand";
cta: { label: string; href: string };
image?: { src: string; alt: string };
};
export function Hero({ heading, subheading, background, cta, image }: HeroProps) {
return (
<section className={heroBackgrounds[background]}>
{/* heading, subheading, button and image */}
</section>
);
}
A page that passes background="blue" or forgets the heading will not compile. Because alt is required on the image object, no hero ships without alt text.
This also documents the library. A developer, or a marketer reading the code, can see from a component's props exactly what it accepts. Keep variant props to the variants that exist in Figma. A free-form className escape hatch on every component is how libraries drift away from the design.
What if Figma variants and code variants diverge?
They will. A designer adds a slightly different card for one campaign, or a hero with a second button, and suddenly the page design no longer matches the component set. You have three options:
- Map it to an existing variant. Often the difference is small enough that the closest existing variant is the right answer. Agree that with the designer rather than building something new.
- Promote it into the system. If the new variant will be reused, add it to the Figma component set first, then to the code. The design file stays the source of truth.
- Keep it page-specific. For a genuine one-off, build a separate section that lives with that page, so it does not add an option to a shared component that every other page has to carry.
The rule I'd hold to: a variant enters the shared library only when it exists in the Figma component set. Keep a short changelog of what was added and why, so the library and the design file can be reconciled later.
Where does the content live?
Somewhere a non-developer can edit it without touching a component. The library decides how a section looks; the content model decides what it says. Whichever you choose, shape the content fields after the section props: if a feature grid takes a heading and three to six items, the CMS should ask for exactly that. When the two match, editors cannot create a page the design does not support.
| Content source | Best for | Trade-off |
|---|---|---|
| Headless CMS | Marketing teams that publish often | Another service to pay for and a schema to maintain |
| Markdown or MDX in the repo | Developer-run sites, docs and blogs | Editors need Git access or a developer to publish |
| Headless WordPress | Teams already comfortable in WordPress | Two systems to host and secure, and preview takes setup |
If you are weighing the last option, my post on headless WordPress with Next.js covers when it is worth the extra moving parts.
How do you document the library?
A library nobody can browse gets duplicated. The simplest fix is a component preview page: a private, noindexed route that renders every section with sample content, at every variant. Storybook does the same job with more tooling, but for most marketing sites a preview route in the same codebase is enough and never falls out of date.
For each component, document four things: the props it takes, the variants it supports, its content limits (heading length, number of items, image ratio) and a link to the matching Figma component. That gives designers, developers and marketers one shared reference.
What does the Figma file not tell you?
The behaviour between and beyond the frames. A design file usually covers one or two viewports, and a website has to hold up on every width from a small phone to a wide monitor. I've built from client Figma files many times, on WordPress rather than Next.js, for clients such as Nortek LED, Orilite and Cyprianis. The stack changes, but the question of what happens between the frames does not.
Ask these before you build
How does each section stack on mobile? What happens to long headings and missing images? What are the hover, focus and disabled states? What does an empty list look like? Agree the answers with the designer once, at the component level.
Other things to settle with the designer:
- Breakpoints. Pick a small set and design to them, rather than fixing every width separately.
- Content limits. Maximum heading lengths and image ratios, so marketers cannot break a section.
- Motion. If the design includes scroll or entrance animation, agree what moves, how long it takes and what happens when reduced motion is turned on. Keep it in a few reusable wrappers rather than per-page code.
- Accessibility. Contrast, focus states and heading order belong in the primitives, so every page inherits them. My free Accessibility Checker reviews a component's code against WCAG 2.2 before it goes into the library.
How do you check the build matches the design?
- 1
Compare at each breakpoint
Put the built section beside the Figma frame at the same width. Check spacing, type and alignment, not just the overall look.
- 2
Stress-test the content
Long headings, short headings, missing images, three cards and seven cards.
- 3
Test on real devices
At least one small phone and one tablet, not only the browser's device mode.
- 4
Check performance
Images sized properly, fonts loaded without layout shift, heavy media as progressive enhancement.
- 5
Review with the designer
Fix differences at the component level, so every page using it gets the fix.
Should your project use Next.js or a WordPress builder?
If developers ship the pages and you want speed and consistency, a Next.js component library is the stronger long-term choice. If your team needs to build layouts visually, a WordPress builder fits better, and my guide to Figma to WordPress pixel-perfect builds covers that route. If you are still undecided, the free Tech Stack Advisor gives a layer-by-layer recommendation based on who will maintain the site. My post on Tailwind CSS for marketing sites goes deeper on the styling side.
If you do not have a design yet, my design partners create the UI and the Figma design system with you through my UI and UX design service, and I build it pixel for pixel. Send me your Figma file through contact and I'll reply with how I'd break it into components.



