Customizing the shadcn Admin: Fork-and-Modify Beats Vendor Widgets
Owning admin code beats living inside a vendor's customisation API — here is why
There are two ways to customise a CMS admin. One is to live inside the vendor's customisation API — a config file, an extension point, an onBeforeSave hook. The other is to fork the code itself and modify it like any other file in your repo. Most CMS vendors offer the first. A shadcn-based admin offers the second.
This post explains how fork-and-modify works in a shadcn CMS, why it beats vendor widget APIs for most real customisation needs, and where the trade-offs are (because there are trade-offs — "just fork it" is not always the right answer).
Disclosure: I work on UnfoldCMS. The customisation story below is the one that ships there, and the comparison is against the vendor-widget approach common in Contentful, Sanity, Strapi, Directus.
TL;DR — vendor widgets vs fork-and-modify
Most CMSs let you customise the admin through their own extension API: a config file, a plugin manifest, a "custom field type" registration. Vendor APIs are constrained — you can do what the vendor expected, no more. Fork-and-modify lets you change anything in the admin code directly because the code lives in your repo. The trade-off: vendor APIs are easier to upgrade (the vendor maintains backwards compatibility); fork-and-modify gives you full control but you handle upstream merges yourself. Across 51 shadcn components and 205 admin pages in UnfoldCMS, about 18 components have local modifications — none of which were possible through a vendor API in the alternatives.
| Customisation type | Vendor widget API | Fork-and-modify |
|---|---|---|
| Add a custom field type | ✅ Yes (designed for it) | ✅ Yes (any way you want) |
| Change a button colour | Maybe via theme config | ✅ Yes (one line) |
| Add a sidebar item | Plugin manifest | ✅ Yes (one line) |
| Re-skin the whole admin | ❌ Usually no | ✅ Yes (Tailwind classes) |
| Replace the post editor entirely | ❌ Almost never | ✅ Yes |
| Change how the DataTable renders rows | Often no | ✅ Yes |
| Upgrade-friendly | Yes (vendor handles BC) | Manual merges on upgrade |
What "vendor widget API" customisation looks like
The dominant pattern in headless CMSs (Contentful, Sanity, Strapi to a lesser degree):
// Pseudo-code — register a custom field type
cms.registerField({
name: 'rating',
type: 'number',
ui: ({ value, onChange }) => <StarRating value={value} onChange={onChange} />,
});
This works for what it was designed for: adding a new field type. It does not let you:
- Change the design of the post-list table.
- Re-arrange the sidebar.
- Replace the rich-text editor with one of your own.
- Re-skin the admin to match your brand.
- Change how validation errors render.
- Add a "duplicate post" button next to "save."
For any of those, you're either out of luck or you need to dig into the vendor's source via patch-package, monkey-patches, or forks of the entire CMS — and those forks aren't supported, so upgrades become painful.
Vendor widget APIs solve 5% of customisation needs and route around the other 95%.
What "fork-and-modify" customisation looks like
In a shadcn-based admin, the 51 components live in cms/resources/js/components/ui/ and the 205 admin pages live in cms/resources/js/pages/admin/. Both directories are in your repo. To customise:
- Change a button colour: open
components/ui/button.tsx, edit the Tailwind variant classes, commit. - Add a sidebar item: open
data/sidebar-data.ts, add the entry, commit. - Re-skin the admin: edit
resources/css/theme.css— CSS variables drive Tailwind v4 theming, three themes ship by default. - Replace the rich-text editor: edit
pages/admin/posts/edit.tsxto use a different editor component. - Change DataTable row rendering: edit
components/ui/data-table.tsxdirectly. - Add a "duplicate post" button: edit the post-list page component, add the button.
Every one of those is a normal pull request — read it, review it, merge it, ship it. No vendor lock-in. No "wait for the vendor to add a hook."
For a deeper walk-through of one specific customisation, see How to Add a Custom shadcn Component to Your CMS.
The compounding effect — why owning the code matters at month 12
Single customisations don't justify either approach. Compounded customisations do.
After a year of building UnfoldCMS on shadcn, the source tree has:
- ~18 components with local modifications (prop additions, focus-ring colors, default tweaks, behaviour changes)
- A custom
<DataTable>that's grown from "ship the basics" to a 400-line component handling column resize, row reorder, server-side pagination, multi-sort, sticky headers - Three production themes (default blue, purple, unfold soft-purple), each one file
- A reworked sidebar component with collapsible groups, badge counters, and recent-items list
- Form patterns specific to CMS shapes (slug-from-title, autosave, SEO sub-section, scheduled publish picker)
None of those would have been possible through a vendor widget API. All of them are unremarkable git commits in a fork-and-modify world.
When vendor widgets are still the right pick
Be fair to the vendor API approach. It wins when:
- Your team is small and time-constrained. A vendor API costs you no source maintenance. Fork-and-modify costs you merge work on every upgrade.
- You only need 5% customisations — add a custom field type, change one icon, that's it. The vendor API was designed for this.
- The vendor supports your customisations under their warranty / SLA. Forks are on you.
- You're a non-developer or low-code team. "Edit
button.tsx" is a developer task; "open the config UI and tick a box" is not.
These are real cases. WordPress's plugin architecture won the 2010s precisely because it lowered the floor — non-developers could customise without forking. shadcn's fork-and-modify approach raises the ceiling — developers can do anything, but it's a developer tool.
The trade-off — merge conflicts on upgrade
The honest cost of fork-and-modify is upgrade merges.
When upstream shadcn changes button.tsx, and you also changed button.tsx, you'll see a merge conflict on the next sync. Resolve it like any other merge. In practice:
- About 60% of upstream component changes are additive (new prop, new variant) and don't conflict with our changes.
- About 30% are mechanical (rename a class, replace
cn()arguments) and conflict trivially. - About 10% are substantive rewrites where you have to genuinely decide: keep ours, take theirs, or merge both.
For UnfoldCMS's 18 modified components over 12 months, the total time spent on upstream merges has been maybe 8 hours total. That's the cost. The benefit was being able to customise anything we needed, when we needed to.
If your team would rather spend zero hours on merges and accept a smaller customisation surface, vendor APIs are the right pick. If you'd rather spend 8 hours over a year and customise anything, fork-and-modify is the right pick.
What "fork-and-modify" doesn't mean
A few clarifications:
- It doesn't mean forking the entire CMS into a different product. That's redistribution, which licensing rules cover separately. Fork-and-modify means modifying the code you ship inside your own sites.
- It doesn't mean ignoring upstream. Pull upstream changes regularly. The whole point is to benefit from upstream improvements while keeping your local customisations.
- It doesn't mean every customisation is wise. "Just fork it" is sometimes the wrong instinct — a vendor's default behaviour exists because they tested it. Fork when you have a real reason; don't fork by default.
For the broader source-available licensing story, see Open-Source CMS Built on shadcn/ui: What Source-Available Means.
People Also Ask
Can I customise the UnfoldCMS admin?
Yes — every shadcn component lives in cms/resources/js/components/ui/ (51 components) and every admin page in cms/resources/js/pages/admin/ (205 pages). Modify any file the same way you'd modify any code in your repo. Commit, deploy, ship.
How does fork-and-modify compare to vendor widget APIs?
Vendor widget APIs (Contentful, Sanity, Strapi to a lesser degree) let you customise inside the vendor's API surface — add field types, register icons, write hooks. Fork-and-modify lets you change anything in the admin code directly because the code lives in your repo. Widgets are easier to upgrade; forks give more control. Pick based on your customisation depth and your tolerance for merge work.
Will my admin customisations survive CMS upgrades?
Yes, with manual merges where upstream changes the same files. About 90% of upstream changes don't conflict at all. The 10% that do are normal git merges — pick a side or combine both. Total merge time across UnfoldCMS's 18 customised components in 12 months has been about 8 hours.
Can I re-skin the entire admin?
Yes. Tailwind v4 CSS variables drive theming. Three themes ship by default (default blue, purple, unfold). Adding a fourth is one file (resources/css/theme.css). See Tailwind v4 + shadcn/ui: Building a Themeable CMS for the longer breakdown.
What if I'm not a developer?
Then fork-and-modify isn't for you, and that's fine. Vendor widget APIs (Contentful, Sanity) are designed for non-developers. UnfoldCMS's fork-and-modify story is a developer tool — it shines when a developer is doing the customisation, not when an editor is.
Bottom line
Vendor widget APIs win when you want to do exactly what the vendor designed for. Fork-and-modify wins when you want to customise anything else. Most real CMS work over 12 months ends up in the "anything else" bucket — sidebar tweaks, table behaviour, theme changes, button shapes. A shadcn-based admin gives you full code access on day one and pays you back for the rest of the project.
Try the UnfoldCMS demo to see the shadcn admin live, or see pricing. The 30-minute test will tell you whether fork-and-modify fits your team.
Sources and methodology
- Component count —
find cms/resources/js/components/ui -name "*.tsx" \| wc -l= 51 in the UnfoldCMS source. - Admin page count —
find cms/resources/js/pages/admin -name "*.tsx" \| wc -l= 205. - Modification count — 18 components with local diffs from upstream, counted by
git logon the UnfoldCMS source tree as of June 2026. - Comparison points verified against vendor docs: Contentful App Framework, Sanity Studio customisation, Strapi plugin docs.
- Merge-effort estimate drawn from UnfoldCMS's internal upgrade logs, April 2024 - June 2026.
Free & Open Source
Own your CMS. No subscriptions.
Unfold CMS is free to download and self-host. Built on Laravel + React, full source code included.
Share this post: