The Real Problem: Your Designer Hands You a Figma File and None of Your Components Match
The handoff goes like this: your designer drops a Figma link in Slack, you open it, and within about 30 seconds you realize their component library looks nothing like what you’ve built. Their “Button/Primary/Large” has a specific border-radius, a shadow token, and a hover state you’d have to manually recreate. Their modal has a backdrop blur. Their data table has frozen columns and row selection states. None of this maps to what you’ve already assembled in code. You’re not starting from scratch, but you’re also not starting from a clean place. That gap β between what’s designed and what’s buildable without a rewrite β is where projects quietly slip deadlines.
The trap I see junior devs fall into constantly: pick a React UI framework based on GitHub stars, wire it up, build half the app, then discover the designer is working in a Figma kit that belongs to a completely different framework. Now you have two choices β convince the designer to redesign in your framework’s kit (good luck), or spend the next two weeks manually matching spacing, typography scales, and component variants by eye. I’ve been in that second situation. It’s miserable and it produces inconsistent UIs. The right question to ask before writing a single line of component code is: does this framework have a Figma kit, and is that the same kit my designer is using?
Here’s where “free Figma assets” gets murky fast. There are three completely different things people mean when they say a framework has free Figma assets, and they are not equivalent:
- Officially maintained kits β built and updated by the framework’s core team or company (e.g., MUI, Chakra UI’s official kit). These stay in sync with the component API. When the framework ships a new prop, the Figma file gets updated too. This is the only category that actually solves the handoff problem.
- Community files β posted by an individual on the Figma Community, sometimes excellent, often abandoned after 6 months. I’ve downloaded community kits that were two major versions behind and missing half the components. Always check the “last updated” date before your designer builds anything on top of it.
- Abandoned repos β somebody started a Figma kit, open-sourced it on GitHub, got a few stars, then stopped maintaining it when they switched jobs. These show up in Google results. The README says “Figma kit included!” and the actual file hasn’t been touched since 2022.
The practical check I do now: open the Figma community file, look at the last update timestamp, count how many components are published versus what the framework’s actual component list shows in its docs. If they diverge significantly β especially on complex components like date pickers, data grids, or command palettes β that kit is going to cause friction. Designers will design something that can’t be replicated with the component’s actual props, and you’ll be building one-off overrides instead of using the system.
One thing that’s changed my workflow on the implementation side: using AI coding tools to accelerate the gap-closing when the Figma kit and the code components don’t perfectly align. If you’re spending time translating Figma specs into component props or building small adapter components to match design tokens, that’s exactly the kind of repetitive work these tools cut down. I’ve covered which ones are actually worth using in the Best AI Coding Tools in 2026 guide β worth reading before you start a project where handoff fidelity matters.
How I’m Judging These (My Criteria, Not a Marketing Checklist)
The Figma file staleness problem is the one that gets me every time. I’ve opened “official” Figma kits that looked polished in the thumbnail, only to find components built with Auto Layout v1, missing variable support, and color styles that don’t match the current library version. The test I run immediately: check the file’s version history. If the last meaningful update was before the library’s 2.x release, the kit is decorative at best. A stale Figma file doesn’t just slow down designers β it means your devs and designers are looking at two different realities from day one.
The 1:1 prop mapping test is where I separate real design systems from marketing assets. Here’s what I actually do: I pick three components β a Button, a Select, and a DataTable β and open both the Figma kit and the component’s TypeScript props in parallel. If the Figma Button has a variant property with options like filled, ghost, outlined, and the actual component accepts variant="contained" | "outlined" | "text", that’s a failure. You’ll spend hours mediating between designers who spec one thing and components that output another. Pretty mockups with zero prop discipline are worse than no kit at all β they create false confidence.
For install experience, I run a clean install and count what npm screams at me before I’ve written a single line. My actual command:
mkdir ui-test && cd ui-test && npx create-react-app . --template typescript
npm install [framework-name] 2>&1 | grep -E "peer dep|WARN|ERR"
Some frameworks come in clean. Others hit you with 8+ peer dependency warnings about conflicting React versions, mismatched @types packages, or legacy packages that need --legacy-peer-deps to even install. That flag is a red flag. If you’re forcing it in a greenfield project, you’ll be fighting it in CI for the next 18 months. I track the exact warning count β zero is ideal, anything above four means the library has housekeeping debt.
TypeScript out of the box means the types ship with the package, not as a separate @types/whatever install that lags behind releases by two versions. I check package.json for "types" or "typings" fields, then immediately try to destructure component props without any explicit typing to see if inference works:
import { Button } from 'some-ui-lib';
// Does this autocomplete without extra config?
const MyBtn = () =>
If my IDE gives me full IntelliSense without a tsconfig.json tweak or a separate types package, I mark it green. If I need to add "moduleResolution": "bundler" or install @types/some-ui-lib separately, I note that β because junior devs will hit that wall and think they broke something.
Bundle size is where I trust tools over claims. Every framework says it supports tree-shaking. Half of them are lying, or at least being optimistic about what their bundler config actually produces. I run a quick bundle analysis:
# Using Next.js for realistic output
npx create-next-app@latest bundle-test --typescript --tailwind --no-src-dir
npm install [framework] @next/bundle-analyzer
# Add to next.config.js:
# const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: true })
npm run build && ANALYZE=true npm run build
Then I import only one component and check what actually ends up in the client bundle. I’ve seen libraries that claim tree-shaking but pull in their entire icon set the moment you touch any component β that’s a 200KB+ hit you didn’t budget for. The threshold I care about: a single Button import should add under 15KB gzipped to your bundle. If it’s pulling 80KB+ for one button, the tree-shaking story is aspirational, not functional.
1. Material UI (MUI) β The One You’ll Default To (For Better or Worse)
Why MUI Ends Up in Every Enterprise Repo (And Why That’s a Mixed Blessing)
The install command alone tells you something about MUI’s philosophy β it’s not just a component library, it’s a stack decision:
npm install @mui/material @emotion/react @emotion/styled
Emotion isn’t optional. I learned this the hard way when I tried to drop it and swap in styled-components on a project where we already had an SC setup. You can technically do it, but you’ll be fighting the library the entire time. MUI v5 made Emotion the default CSS-in-JS engine, and the integration is deep enough that stubbing it out costs more than just running both. Accept it early and move on.
The Figma Kit Is Actually Maintained (Which Is Rare)
Search “MUI for Figma” in the Figma Community and you’ll find the official file. The free tier covers all the core components β Buttons, Inputs, Cards, Navigation, Data Grid shells. What surprised me was that the Figma components aren’t just cosmetic mockups. They use Auto Layout correctly, and the component properties map to real API props. The variant property in Figma (outlined, filled, standard for inputs; text, outlined, contained for buttons) directly mirrors what you’d pass in JSX. When I handed a design file to a junior dev, they could look at the Figma prop panel and write the component without guessing:
<Button variant="contained" size="large" color="secondary">
Submit
</Button>
That 1:1 mapping between design props and component API is genuinely useful β most Figma kits from third parties don’t bother with this level of fidelity.
Where It Gets Painful: Theming and Style Overrides
The thing that caught me off guard wasn’t the initial setup β it was what happens three weeks into a project when the design team wants to adjust the default border radius globally and change how the primary color interacts with hover states. createTheme() is powerful but the mental model takes real time to build. You’re not just setting values, you’re understanding a cascade of tokens that reference each other:
const theme = createTheme({
palette: {
primary: {
main: '#1a73e8',
},
},
shape: {
borderRadius: 8,
},
components: {
MuiButton: {
styleOverrides: {
root: {
textTransform: 'none',
},
},
},
},
});
That last part β styleOverrides β is where things get messy at scale. When you need to override styles on a nested element inside a component (say, the input label inside a TextField), you’re reaching for sx prop hacks or hunting through MUI’s source to find the right slot name. I’ve spent 45 minutes on a single component override that should have taken five. The docs have gotten better, but the CSS specificity battles are real.
Honest Assessment: Right Tool, Wrong Project
MUI is genuinely good for internal tooling, admin dashboards, and data-heavy enterprise UIs. The Data Grid component alone justifies the install for those use cases. But I’ve made the mistake of reaching for it on a marketing site and a startup landing page, and both times I regretted it. Even with tree-shaking, the v5 bundle is heavy. You’re pulling in Emotion’s runtime, the MUI core, and all the component styles β and if you’re not disciplined about imports, you’ll see it in your Lighthouse scores. For a marketing site where every kilobyte matters and the design deviates from Material Design conventions, you’ll spend more time fighting the defaults than building features.
Use MUI when: your team is small, you need to ship fast, the UI is functional over decorative, and you’re building something where the Material Design language won’t clash with your brand. Skip it when: your designer has a strong custom system, you’re building a consumer-facing product with heavy animation requirements, or you’re already deep in Tailwind and don’t want two styling systems fighting each other.
2. shadcn/ui β Not Exactly a Framework, Which Is the Point
shadcn/ui flips the normal framework model on its head. Instead of installing a package and importing from it, you run a CLI command that writes source files into your project. The component is now yours β you can read it, edit it, delete parts of it, and it won’t break on the next npm update because there’s nothing to update. I switched to this approach after spending too many hours fighting with a Material UI upgrade that changed half the prop API between major versions.
The install flow is exactly as clean as it sounds. You initialize once:
npx shadcn-ui@latest init
That walks you through your Tailwind config path, your preferred CSS variables setup, and where your components/ folder lives. Then you add components individually:
npx shadcn-ui@latest add button
npx shadcn-ui@latest add dialog
npx shadcn-ui@latest add command
Each command drops a file directly into /components/ui/. Open button.tsx and you’ll see it’s built on @radix-ui/react-slot with class-variance-authority for variant handling. No mystery, no abstraction you have to trust blindly. That transparency matters more than it sounds when you’re debugging a z-index issue at 11pm.
The thing that caught me off guard was the Figma community file. Most UI kits are maintained by someone who built the components once and then drifted. The official shadcn/ui Figma file is actually kept in sync with the CLI β and more importantly, the component names match exactly. The Figma frame called “Button” corresponds to what npx shadcn-ui@latest add button generates. That 1:1 naming means handoffs between design and dev don’t turn into a guessing game of “is this the outlined variant or the ghost variant?” The file also uses Tailwind color token names like primary, muted-foreground, and destructive β which map directly to what you define in your tailwind.config.js under the colors key. You can sync your custom palette in both places and the Figma mocks will actually reflect your real brand colors.
Here’s the gotcha that gets people: skip npx shadcn-ui@latest init and your components will install but your theme won’t work. The init step writes CSS custom properties into your globals.css and updates your tailwind.config.js to extend the color palette with variables like --background, --foreground, --primary. If those aren’t there, every component will render with broken or fallback colors. I’ve seen developers add shadcn to an existing Tailwind project, skip init because they thought it was optional, and then spend an hour wondering why the Button variant styling wasn’t applying. Run init. Read what it changes. Then add components.
shadcn/ui is the right call specifically for Next.js projects where you want a design system that you actually own. It’s not the right call if you need a drop-in solution fast and don’t want to think about how components are structured β for that, grab Chakra or Ant Design. But if you’re building a product that’ll need to deviate from defaults, have a designer involved who works in Figma, and care about not being locked into a library’s release schedule, this is the one I’d pick. The free Figma kit being officially maintained and token-aware is a genuine differentiator β most competitors make you choose between good DX or a usable design file. shadcn gives you both.
3. Chakra UI β The One That Nails Accessibility Without Making You Think About It
The accessibility story is what got me. I’ve used component libraries where you ship something, run an audit, and spend two days patching aria-label attributes and fixing focus traps. With Chakra UI, I’ve genuinely never had to manually add a role or any aria-* attribute. The Modal traps focus correctly. The Menu responds to arrow keys. The Checkbox and RadioGroup announce themselves properly to screen readers. That’s not a small thing β if your acceptance criteria include WCAG 2.1 AA compliance, Chakra basically does the boring parts for you out of the box.
Installation has one gotcha that trips people up the first time:
npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion
Framer Motion is a hard dependency, not optional. You need it even if you have zero interest in animations. That adds roughly 50KB gzipped to your bundle. If you’re on a strict performance budget, factor that in before committing. After install, wrap your app with ChakraProvider and you’re building immediately β no config file, no theme token setup unless you want it.
The props-as-styles API has a learning curve of about one afternoon, and then it clicks permanently. Instead of context-switching to a CSS file or a styled-component, you write:
<Box p={4} mt={2} color="gray.700" borderRadius="md" bg="white">
<Text fontSize="sm" fontWeight="semibold">Card content</Text>
</Box>
The numbers map to Chakra’s spacing scale (4 = 1rem), the color strings reference the built-in palette, and the whole thing stays readable without hunting through stylesheets. I’ve prototyped full dashboards faster with this pattern than with any other library I’ve used. The responsive shorthand also doesn’t suck β fontSize={["sm", "md", "lg"]} maps to your breakpoints without additional CSS.
The Figma Kit Situation (Read Before Designing)
Search “Chakra UI Design System” in Figma Community and you’ll find the official community file. It’s genuinely well-structured β components are organized logically, auto-layout is used throughout, and the token naming mostly mirrors what you’d write in code. The problem as of mid-2024 is the v3 migration. Chakra v3 renamed several components and restructured some APIs, and not every community Figma file has caught up. Before your designer builds out a full screen using, say, FormControl and its sub-components, verify the Figma component name matches the actual v3 import. FormControl still exists but several of its child patterns changed. Spending 20 minutes cross-referencing the Figma file against the v3 changelog will save you a painful handoff conversation later.
When Chakra Is the Right Pick vs. When It Isn’t
- Use Chakra if: accessibility is a first-class requirement, you want a design system that’s good enough out of the box without a dedicated designer, or you’re building internal tooling where customization needs are moderate.
- Skip Chakra if: your bundle size constraints are aggressive (Framer Motion adds weight you might not need), you want raw unstyled primitives that don’t ship any default visual opinions, or your design team lives entirely in a Figma file that predates v3 and won’t update it.
Honest take: Chakra is my default recommendation when a client hands me a spec with “must pass accessibility audit” in the requirements. It removes an entire category of QA issues without you having to think about them. The v3 Figma sync lag is real and annoying, but it’s a process problem you can work around β the underlying component quality makes it worth it.
4. Ant Design β Enterprise-Grade and It Knows It
The install is the easiest part β everything after takes more time than you’d expect
Getting Ant Design running is genuinely painless:
npm install antd
No peer dependency warnings, no “please also install these 4 companion packages.” Just antd. Compare that to some other frameworks where you spend 20 minutes reconciling peer deps before writing a single line of code. That said, the smooth install lulls you into thinking setup is done. It isn’t. The first gotcha hits you when you check your bundle size after adding a couple of components β antd’s full package is enormous. Without proper tree-shaking, you’re shipping a massive chunk of JavaScript for components you never touched.
The fix depends on your build setup. With Babel, add babel-plugin-import:
// .babelrc
{
"plugins": [
["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
]
}
If you’re on Vite (and you should be, for new projects), skip the Babel plugin entirely and use the ES module build directly β Vite’s tree-shaking handles it. Just import components named from antd and check your bundle after. I got burned on this once by copy-pasting an old Webpack config into a Vite project and wondering why my bundle looked wrong.
The Figma kit is genuinely one of the best I’ve used
Head to ant.design/docs/resources and grab the official Figma Community file. The thing that caught me off guard was how organized it actually is β components are grouped by category, every component has multiple variants, interaction states are documented (hover, focus, disabled, error), and they’ve included dark mode tokens. Most free Figma kits give you a flat list of artboards that look nothing like the actual components. Ant Design’s kit is the opposite. Your designer can hand off specs using this and you’ll recognize every element when you go to implement it. That alone saves hours of back-and-forth.
60+ components, including the ones other libraries make you build yourself
MUI has a decent component set, but some things you just have to wire up yourself. Ant Design ships a Transfer component (dual-panel picker), a TreeSelect, and a Table with virtual scrolling baked in. That Table is the real reason I’ve reached for antd on data-heavy admin panels β handling 10,000+ rows without a custom virtualization setup is huge. Here’s the basic virtual scroll table setup:
import { Table } from 'antd';
<Table
columns={columns}
dataSource={data}
scroll={{ y: 500 }}
virtual
/>
The virtual prop does the heavy lifting. You don’t need to install react-window or react-virtual or configure any windowing logic β it just works. For an internal dashboard showing audit logs or transaction history, that’s the kind of thing that makes antd the right call.
The default aesthetic is a real issue for consumer products
I’ll be direct: antd out of the box looks like internal tooling built for a large Chinese tech company. That’s not a criticism of the quality β the components are solid β but the visual language is very enterprise SaaS. If you’re building a consumer-facing product, you’ll spend significant time fighting the defaults. The customization path goes through ConfigProvider and the design token system:
import { ConfigProvider } from 'antd';
<ConfigProvider
theme={{
token: {
colorPrimary: '#6366f1',
borderRadius: 8,
fontFamily: 'Inter, sans-serif',
},
}}
>
<App />
</ConfigProvider>
This looks clean, but the token system has over 200 tokens and understanding which ones cascade into which components takes real time. I spent a full afternoon once trying to figure out why a DatePicker dropdown wasn’t respecting my border-radius override β turns out it uses a separate popup token. The docs cover it, but you have to dig. For an internal tool where you ship fast and aesthetics are secondary, it’s fine. For a product where design fidelity matters, budget a few days for theming work before your first demo.
My honest recommendation: reach for Ant Design specifically when you’re building internal tools, admin dashboards, or data-heavy interfaces where the component depth pays for itself. If you’re building something user-facing where visual polish and brand expression are priorities, you’ll spend more time undoing antd’s defaults than you’d spend building on a lighter foundation.
5. Mantine β The Underrated One I Actually Switched To for New Projects
I switched from Chakra UI to Mantine about eight months ago, and the tipping point was a single component: DatePicker. I needed a date range picker with time input, and Chakra wanted me to install a third-party package, configure it, fight with its Chakra-specific prop API, and pray the maintainer hadn’t abandoned it. Mantine just had it. Built in. Styled correctly. Working on first render. That’s the pattern you’ll see across Mantine β the components are genuinely complete, not MVP shells waiting for a community wrapper.
Installation Is Actually Just Two Lines
npm install @mantine/core @mantine/hooks
Wrap your app in <MantineProvider> and you’re running. No separate Emotion peer dependency config, no GlobalStyles component you have to remember to add, no theme provider nesting puzzle. That’s because v7 ditched Emotion entirely and moved to CSS modules. The practical effect: zero runtime style injection overhead. On a mid-complexity dashboard I benchmarked, TTI dropped noticeably after migrating from a Chakra-based codebase β not because Mantine is magic, but because it’s not generating styles in JavaScript on every render.
The Figma Kit Doesn’t Feel Like an Afterthought
Search Mantine UI in the Figma Community. The official file is maintained by the core team and versioned alongside releases β so when v7 shipped a redesigned Select component, the Figma file updated to match. That’s the thing that kills most free Figma kits: they’re built once, never touched again, and after six months they don’t match what’s actually in the npm package. With Mantine’s kit, when you hand a designer a component from the file, the developer can actually build it without improvising. The component states (hover, error, disabled, loading) are all there. Responsive variants exist. It’s the difference between a reference file and a working design system artifact.
The Hooks Package Is Worth Installing Even If You Don’t Use the UI
@mantine/hooks is a standalone package, and I genuinely use it in projects that have nothing to do with Mantine components. useLocalStorage handles serialization and cross-tab sync out of the box. useMediaQuery works SSR-safe, which matters if you’re on Next.js and tired of hydration mismatches from naive window.innerWidth checks. useClickOutside handles the ref wiring you’d otherwise write for the fifth time in your career. None of these are revolutionary hooks, but they’re implemented correctly β edge cases handled, TypeScript types solid β and having them in a single stable package beats copying Stack Overflow snippets into a /utils folder.
Where It Actually Gets Rough
The ecosystem gap versus MUI is real. If you’re reaching for react-hook-form with MUI, there are battle-tested controller wrappers and documented patterns everywhere. With Mantine, you’re wiring it yourself. That’s not hard β Mantine’s form components expose onChange and value cleanly β but you’re writing the glue code, and that adds up across a large form-heavy app. Same story with data grid components: MUI has DataGrid, Mantine has… Table. Fine for simple cases, but if you need virtualization, column resizing, and row selection, you’re integrating TanStack Table manually. The Mantine team knows this and has been building out the ecosystem, but right now it’s still a gap worth knowing about before you commit.
That said, for new SaaS projects β dashboard, settings pages, admin panels, onboarding flows β Mantine is my default now. The DX is clean, v7 performance is noticeably better than v6 (the CSS modules migration wasn’t just ideological), and the Figma file means designers and developers are actually looking at the same thing. If your team is already deep in MUI with existing patterns and integrations, there’s no reason to migrate. But for a greenfield project? Start here.
Side-by-Side: What Actually Matters When Picking One
The Figma file quality column is the one most devs skip, and it’s the one that bites them hardest. I’ve seen teams pick Ant Design for a dashboard project purely because the component count looked impressive, then spend two weeks reconciling spacing tokens that don’t map to anything in the codebase. So before I walk through the table, here’s the thing that actually matters: a Figma file is only useful if your designer can hand you a spec and the values in it already exist in your theme config. If they don’t, you’re translating by hand every sprint.
| Framework | Figma File Quality | Figma β Code Token Sync | Install Complexity | Bundle Size Impact | Best Fit |
|---|---|---|---|---|---|
| MUI | High | Medium β tokens sync via MUI X, Emotion setup required | Medium | Large | Enterprise dashboards |
| shadcn/ui | Perfect | Low friction β Tailwind tokens sync natively | Low | Minimal (you own the code) | Next.js apps, full control |
| Chakra UI | Good, v3 catching up | Medium β Emotion setup adds overhead | Medium | Medium | Accessibility-first apps |
| Ant Design | Best Figma file of the five | Low β lots of config to get tokens flowing | Low (simple install) | Large without tree-shaking | Internal tools, data tables |
| Mantine | Well-maintained, updated with releases | Medium-High β CSS modules in v7 simplified things | Low | Small | New SaaS projects |
The install complexity column is deceptive. Ant Design’s “simple install” is technically true β npm install antd and you’re moving. But if you want design tokens to actually flow from Figma into your theme, you’re wiring up a ConfigProvider with a custom theme object, mapping Figma variable names to AntD’s token API by hand, and hoping your designer used the right layer naming conventions in the Figma file. I switched a project off Ant Design mid-sprint because the token reconciliation alone added a day of work every time the designer updated the color palette. For internal tooling where the designer is the developer, that’s fine. For cross-functional teams, it’s friction that compounds.
shadcn/ui’s “perfect” Figma score comes with an asterisk that I actually mean as a compliment: the reason token sync is frictionless is that Tailwind CSS variables are the tokens. Your Figma file uses CSS variable names like --background, --primary, --muted-foreground, and those exact names live in your globals.css. There’s no translation layer. I’ve used this setup on a Next.js 14 project and the handoff from design to implementation dropped from a multi-hour discussion to a five-minute diff. The trade-off is that you own every component file β shadcn copies the source into your repo via npx shadcn-ui@latest add button, so updates aren’t automatic. That’s a feature for some teams and a maintenance headache for others.
Bundle size is the column that causes the most disagreement in code reviews, and honestly the “Large” label on MUI and Ant Design is only the full story if you’re not tree-shaking properly. With Ant Design, if you’re on v5 and you’re importing like this:
import { Button, Table, DatePicker } from 'antd';
β¦you’re getting tree-shaking out of the box in v5 because it ships ES modules. But in v4, you needed babel-plugin-import configured explicitly or you were shipping the full library. A lot of teams I’ve talked to are still mentally carrying the v4 baggage. MUI v5+ handles tree-shaking similarly, but the Emotion runtime itself adds to your initial JS regardless β you’re looking at roughly 30β40KB gzipped just for the styling engine before a single component. Mantine v7 dropped Emotion entirely for CSS modules, which is why its bundle impact is listed as small. That was a painful migration for existing Mantine users but the right call long-term.
My actual decision tree looks like this: if you’re starting a new SaaS product in 2025 and want Figma-to-code to feel like a first-class workflow, start with shadcn/ui or Mantine. shadcn if your team knows Tailwind cold and wants zero abstraction; Mantine if you want a proper component API with hooks like useForm, useDisclosure, and useDebouncedValue baked in. MUI makes sense when you’re joining an existing enterprise project that already has a MUI design system β don’t rip it out, just learn the sx prop and theme customization deeply. Chakra is solid if WCAG compliance is a hard requirement and you want components that handle ARIA attributes without fighting the library. Ant Design is my go-to recommendation for internal admin dashboards where the Figma file fidelity matters more than bundle size, and the users are on fast corporate networks anyway.
When to Pick What: Match the Framework to Your Situation
Match the Framework to Your Situation
The worst decision I see teams make is picking a UI framework based on GitHub stars or what was trending when someone wrote the project proposal. The second worst is switching frameworks six months in because nobody thought hard enough upfront. So here’s how I actually think through this decision when a new project lands.
You have a designer already working in Figma and you need tight handoff
Go with shadcn/ui. Full stop. The reason the Figma-to-code gap is narrowest here is the Tailwind token system β your designer sets up CSS custom properties in Figma using the Tailwind config values, and those tokens map directly to what you’re writing in JSX. There’s no translation layer where a primary-600 in Figma becomes #2563eb in code and then drifts over three sprints. I’ve worked with designers who can drop a component spec and I can implement it without a single back-and-forth message, purely because the vocabulary is identical on both sides.
The catch nobody tells you upfront: shadcn/ui is not a dependency, it’s a code generator. When you run npx shadcn-ui@latest add button, that component lands in your components/ui/ directory and it’s yours. That’s the power and the risk. You own the code, so updates don’t break you, but you also own the maintenance. If shadcn ships a better Dialog in six months, you’re manually reconciling diffs. For a designer-developer pair doing a tight product build, the trade-off is worth it. For a team of twelve junior devs who need consistent updates? Think twice.
You’re building an internal admin tool with complex tables and data visualization
Ant Design is the answer, and the component breadth is the entire reason. I tried to replicate an AntD-level data table with sorting, filtering, virtual scrolling, and expandable rows using a lighter framework once. I spent four days. With AntD’s Table component, the first working prototype was done before lunch. The component catalog is genuinely exhaustive in a way that saves you from building infrastructure.
The setup cost is real though. Bundle size is the obvious issue β antd is heavy, and if you’re not configuring tree shaking correctly in your Vite or webpack config, you’ll bloat the bundle fast. The other thing that caught me off guard was the theming system. AntD v5 moved to CSS-in-JS with a design token API, which is powerful but means your theme config looks like this:
import { ConfigProvider } from 'antd';
<ConfigProvider
theme={{
token: {
colorPrimary: '#1677ff',
borderRadius: 6,
},
}}
>
<App />
</ConfigProvider>
That’s fine until you try to integrate it with Tailwind, and then you’re managing two parallel token systems. For pure admin tools where Tailwind isn’t in the picture, AntD is the most productive framework I’ve used for dense, data-heavy UIs. Bring Tailwind into that mix and you’re in for some friction.
Your client has WCAG 2.1 compliance written into the contract
Use Chakra UI and don’t try to retrofit accessibility into something else. I made that mistake once with a different framework on a healthcare project. We spent the last three weeks before launch running axe audits, manually patching focus management, adding missing aria- attributes, and arguing about color contrast ratios. The client had a real accessibility requirement and the framework we chose treated it as an afterthought.
Chakra is built on top of Radix UI primitives under the hood, which means the focus trapping, keyboard navigation, and ARIA roles are correct from day one. The useColorModeValue hook makes contrast compliance straightforward since you’re always pairing light and dark values explicitly. The Figma kit Chakra ships is solid enough for most projects β not as polished as some, but the components map cleanly to what you build in code. For a compliance-driven project, that predictability is worth more than a pretty Figma file.
You’re starting a new SaaS and want to move fast without regrets at the six-month mark
Mantine v7 is where I’d put money right now. The hooks library alone β useForm, useDisclosure, useIntersection, useDebouncedValue β eliminates a chunk of utility code you’d otherwise write from scratch. The component set is thorough without being overwhelming, the TypeScript types are tight and don’t fight you, and the documentation is genuinely one of the better ones in the ecosystem. I’ve found answers in the Mantine docs on the first search more consistently than with most other frameworks.
The Figma community kit for Mantine is community-maintained rather than official, which is the honest trade-off to name here. It’s not as meticulously maintained as MUI’s official Figma library. If your designer is Figma-first and expects pixel-perfect kit components, flag this early. If you’re a developer-heavy team or a solo founder doing your own design, it won’t matter much. The velocity benefit of Mantine is real β I’ve shipped production-quality dashboards in a weekend with it, and the codebase didn’t feel like something to apologize for six months later.
Your team already knows MUI and the project is enterprise
Just use MUI. I know the cool thing to say is “MUI is heavy and opinionated and hard to customize” β and all of that is true. But if four developers on your team have two years of MUI muscle memory, the switching cost to anything else will hurt you more than MUI’s limitations. The sx prop for one-off overrides, the styled() utility, the theme provider β they know it. That knowledge is worth real sprint velocity.
MUI also has the most thorough official Figma kit of any framework on this list. The MUI for Figma package maps almost every component to its design spec with the correct variants, states, and props documented. For enterprise projects where the designer and developer handoff needs to be auditable and consistent across a large team, that matters. The MUI component grid alone has saved me from writing boilerplate layout code I never want to write again. The footgun is customizing deeply away from Material Design β once you’re fighting the theme to make things look non-Google, you start questioning all your choices. Stay close to the defaults, extend carefully, and it stays manageable.
How to Verify a Figma Kit Is Actually Maintained Before You Commit
The single fastest way to burn a week of design-to-dev time is syncing with a Figma kit that was built for version 4 of a library that’s now on version 7. So before you duplicate any community file, open the file’s Community page and look at the Last updated date β it’s right under the file title. If that date is more than 12 months ago and the npm package has had multiple major releases since, close the tab. That kit is a snapshot of a past state, and you’ll spend more time reverse-engineering the gaps than you would have just building the components yourself.
The next thing I do β and this takes literally 5 minutes β is open the Figma file, grab the names of 10 or so components, and cross-reference them against the library’s current docs. I’m specifically checking whether a component called Button in Figma still maps to a <Button> in the npm package with the same prop names. A Figma kit made for Chakra UI v2 will show a colorScheme prop structure that’s been deprecated in v3, which means every handoff spec your designer produces is technically wrong before dev even touches it. This isn’t paranoia β I’ve hit this exact mismatch with two popular “community favorite” kits that had thousands of duplicates but hadn’t been touched since the framework rewrote its theming system.
Design tokens are the real tell. Open the Figma file and hit Edit β Find/Replace or just click into a few component fills. If you’re seeing raw hex values like #6366F1 hardcoded directly on shapes instead of variables like color/primary/500, the kit won’t scale with your theme. You won’t be able to switch between light and dark mode cleanly, and any brand customization means hunting through hundreds of individual layers. A properly maintained kit will use Figma Variables (the feature that shipped in 2023) or at minimum local styles tied to a token structure. If it’s just static frames with hardcoded values, someone exported it from Storybook once and called it a day.
The most reliable signal is GitHub. Pull up the framework’s releases page β something like github.com/shadcn-ui/ui/releases β and check whether the Figma kit versions roughly track the npm release history. If the npm package is at v5.2.1 but the Figma kit’s last version bump was v3.0, that’s not a maintained resource, that’s a community contribution someone made during a weekend sprint and never revisited. Frameworks that take their Figma kits seriously β and a few do β will have a changelog either in the file description or linked from the docs site. If you can’t find any versioning info at all, assume the file is frozen in time.
Quick Verification Checklist Before You Commit to a Kit
- Last updated date on Community page β flag anything older than 12 months if there have been major npm releases in that window
- Component name audit β spot-check 10 components against the current npm docs; pay attention to prop names, not just component names
- Figma Variables or local styles β if fills are hardcoded hex, the kit won’t support theming without a full redo
- GitHub releases cross-reference β kit versions should roughly track npm versions; a gap of 2+ major versions is a red flag
- File description changelog β maintained kits document what changed; undocumented kits are usually abandoned ones
One gotcha I didn’t expect the first time: a kit can pass all of the above checks and still be broken in a subtle way. I found a Material UI kit that had correct component names, used local styles, and had been updated 3 months prior β but the grid system was built on an 8-column layout while MUI’s actual grid defaults to 12 columns. Everything looked right in Figma and fell apart the second a developer tried to implement a spec. If the kit doesn’t include a basic layout frame showing the grid, or doesn’t document the base spacing unit, ask in the comments before committing. The comments on a Figma Community file are actually one of the best signals β if people are posting “this doesn’t match v5” and the author hasn’t responded in 6 months, you have your answer.