Figma to Next.js: how to build a reusable component library

How to turn a Figma design into a Next.js component library: tokens first, then primitives, sections and typed props, with Tailwind.

Mohit Goyal8 min readUpdated 2 Nov 2026
Figma to Next.js: how to build a reusable component library

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 FigmaIn the Next.js codebase
Colour and text stylesDesign tokens in the Tailwind theme
Spacing and layout gridSpacing scale and container components
Components and variantsReact components with typed variant props
Auto layoutFlexbox and grid utilities
Frames for desktop and mobileResponsive classes at agreed breakpoints
A page designA 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?

Rendering diagram…

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:

tsx
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 sourceBest forTrade-off
Headless CMSMarketing teams that publish oftenAnother service to pay for and a schema to maintain
Markdown or MDX in the repoDeveloper-run sites, docs and blogsEditors need Git access or a developer to publish
Headless WordPressTeams already comfortable in WordPressTwo 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. 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. 2

    Stress-test the content

    Long headings, short headings, missing images, three cards and seven cards.

  3. 3

    Test on real devices

    At least one small phone and one tablet, not only the browser's device mode.

  4. 4

    Check performance

    Images sized properly, fonts loaded without layout shift, heavy media as progressive enhancement.

  5. 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.

Frequently asked

How do you convert a Figma design to Next.js?+

Turn the Figma styles into design tokens in your Tailwind theme, build small primitives such as buttons and headings, compose them into page sections, and assemble pages from those sections. Check each against the Figma file at every breakpoint.

Can Figma export React code directly?+

Plugins can generate code, but it is rarely what you want to maintain. Generated code copies one frame at one size. A hand-built component library encodes the design's rules and works at every screen size.

What is the difference between a design system and a component library?+

The design system is the set of decisions: colours, type, spacing and components, usually in Figma. The component library is that system built in code, which developers and marketers use to make pages.

Do I need a design system before building in Next.js?+

It helps a great deal. Without one, every page reinvents spacing and type. If you have only page designs, the first job is to extract the system from them.

Can marketers build pages from a component library?+

Yes, if the content model allows it. With a library of tested sections, a new page is a list of sections and some content, not a fresh build.

Mohit Goyal

Written by Mohit Goyal

Senior Web Developer in Gurugram, India. 100+ fast, SEO-friendly sites shipped in 4+ years with Next.js, React and WordPress, including the procol.ai rebuild. Send me your next project.

Keep reading

Is Tailwind CSS a good choice for a marketing website?

Tailwind CSS suits marketing sites built in Next.js or React. When it helps, when a page builder is better, and how to set it up for a team.

8 min read

Hire a freelance React developer: rates and what to check

What a freelance React website developer charges in USD and GBP, where to hire one, and the checks to run before you pay a deposit.

22 min read

Let's build

Have a site that needs to be fast, rank and convert?

Open to Work. Usually replies within a day.