# ui-builder: a Figma-style editor inside your own React app

> UI Builder is a shadcn/ui package that adds a visual, no-code editor to a product you already ship, letting non-developers compose pages, emails and dashboards from the exact React components in your codebase. Layouts are saved as plain JSON, and the component registry is the contract that keeps the output on-brand.

**olliethedev/ui-builder** — A React component that provides a no-code, visual way to create UIs, compatible with shadcn/ui and custom components.

- Repository: https://github.com/olliethedev/ui-builder
- Website: https://www.uibuilder.app/
- Stars: 671 · Forks: 96
- Language: TypeScript
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/olliethedev-ui-builder

## An editor inside your product, not a page builder for the web

The framing of UI Builder is unusual enough to state precisely, because most tools in this space do something different. The README describes it as a shadcn/ui package that adds a Figma-style editor to your own product, letting non-developers compose pages, emails, dashboards and white-label views with the exact React components you already ship. So this is not a visual builder that emits code for a landing page, and it is not a generic canvas. It is an editing surface embedded in an application, where the palette is your component library and the output is a layout your application renders. That design has two consequences. The first is that the visual result cannot drift from the design system, because there is nowhere else for a non-developer's button to come from. The second is that the result is data rather than code, since layouts are saved as plain JSON for easy versioning and can be rendered instantly with dynamic data. The audience is therefore a product team that has a set of approved components and a set of users who need to arrange them without writing React, and the repository is a Next.js application with the editor packaged for consumption through the shadcn registry mechanism.

## The component registry is the contract

Everything in the editor is driven by a component registry, and understanding it is the whole learning curve. A registry maps a component name to a React component, a schema describing the props a user may set, and the import path the component came from. The README's example starts from the primitive component definitions that ship with the package and then adds one application component, a Button, whose schema is built with zod.

```tsx
const myComponentRegistry: ComponentRegistry = {
  ...primitiveComponentDefinitions,
  Button: {
    component: Button,
    schema: z.object({
      className: z.string().optional(),
      children: z.any().optional(),
      variant: z.enum(["default", "destructive", "outline", "secondary", "ghost", "link"]).default("default"),
    }),
    from: "@/components/ui/button",
  },
};
```

The schema is what turns a prop into something an editor can offer. The Button entry declares className and children as optional strings, and constrains variant to a fixed set of values with a default, which is what lets the inspector show a dropdown rather than a free text field. The from field records where the component lives, which is the piece that makes a saved layout resolvable by the application that renders it. Since the registry is a prop, as the breaking changes section notes, you pass it to the editor component and the editor uses it as the entire palette. Everything the designer can place, and every property they can change, is a consequence of what you put in this object, which is why the extension point for custom components is the same mechanism as the built-in ones.

## Layouts as JSON, and variables for the dynamic part

The output format is the second half of the design. Layouts are saved as plain JSON, which the README describes as making them easy to version, and the documentation lists a Variables page for dynamic data binding and a Rendering Pages page for rendering saved layouts. The distinction matters operationally. A JSON layout is a value that can be stored in a database row, put in version control, diffed in a pull request, and rolled back. It is also something you can validate, since the same schemas that describe component props can describe what a layout is allowed to contain. The variables feature is what keeps the layout from being a static picture, since the difference between a saved layout and a working page is the data that fills it in, and a binding mechanism lets one layout serve many records. The upshot for a product team is that non-developers change a value rather than a file, and that change is reviewable in the same system as everything else. The documentation also covers custom components and the shadcn registry, which are the two routes by which the palette grows beyond what the package ships.

## Installing it through the shadcn registry

Installation happens through the shadcn CLI and a registry file hosted in the repository, which means the editor lands in your source tree rather than in a package you depend on. If you already have a shadcn/ui project, the README gives one command.

```bash
npx shadcn@latest add https://raw.githubusercontent.com/olliethedev/ui-builder/main/registry/block-registry.json
```

Starting a new Next.js project with UI Builder is the same command with an init and a base colour.

```bash
npx shadcn@latest init https://raw.githubusercontent.com/olliethedev/ui-builder/main/registry/block-registry.json --base-color zinc
```

Two optional installs extend the palette. One registry adds the full shadcn component library, which the README describes as 54 pre-configured components and 124 block templates, and the other adds React Email support for building email templates in the editor.

```bash
npx shadcn@latest add https://raw.githubusercontent.com/olliethedev/ui-builder/main/registry/shadcn-components-registry.json
npx shadcn@latest add https://raw.githubusercontent.com/olliethedev/ui-builder/main/registry/react-email-components-registry.json
```

There is one installation wrinkle the README handles head on. Peer dependency warnings are common with React 19, and the suggested fix is a .npmrc file containing a single line.

```bash
echo "legacy-peer-deps=true" > .npmrc
```

That is a real trade rather than a freebie, since legacy peer deps means npm stops enforcing the peer version ranges, so it is worth checking afterwards that the editor still works with your React version rather than assuming the warning was noise.

## Email templates and the polyfill Safari needs

The React Email registry is more than a list of components. It installs the react-email component registry plus email specific builder utilities, and the README names them, with emailPageRenderer, emailCodeGenerator and DEFAULT_EMAIL_TAILWIND_CONFIG. Those names tell you what the email path does differently. An email is not a page: it is rendered by an email client, not a browser, and the styles that work in the editor are not necessarily the styles that survive that trip. The email renderer utility and the email specific Tailwind configuration are what bridge the gap between the visual editor and the output that an inbox can render, and the code generator covers the case where a recipient needs the template as code rather than as a sent message. There is also a compatibility instruction that is easy to skip and expensive to skip. For Safari and iOS compatibility with the react-email render package, the README asks you to add a web streams polyfill import at the top of your email route entry file.

```ts
import "web-streams-polyfill/polyfill";
```

That is a platform dependency on modern stream APIs, which does not exist in Safari and iOS out of the box, and it explains why the email route is called out separately from the page rendering route.

## Theming through style variables, and hiding the theme panel

Theming is handled by the recommendation in the README to use style variables for proper page theming, which is the shadcn/ui convention, and the editor follows it rather than inventing its own. The panel that exposes those variables is the TailwindThemePanel, which appears in the Appearance tab, and the README shows how to remove it or replace it without rewiring the panel system. Passing false hides it.

```tsx
<UIBuilder
  componentRegistry={myComponentRegistry}
  tailwindThemePanel={false} // hide panel
/>
```

Passing a node replaces it with your own component, which is the more interesting of the two options, because it means a product can offer its own theme controls, a set of brand presets, or a restricted palette without forking the editor.

```tsx
<UIBuilder
  componentRegistry={myComponentRegistry}
  tailwindThemePanel={<MyCustomThemePanel />}
/>
```

The design here is deliberately narrow, and that narrowness is the point. Rather than replacing full panel wiring, the prop lets you change one part of the appearance experience, which is a smaller change to maintain than the alternative would be.

## Version churn, the move to BTST, and who should adopt it

Two things in the README should change how you evaluate this package. The first is the breaking changes section, which records real structural churn. Version 2.0.0 changed the internal structure and instructs you to delete the old ui-builder and lib/ui-builder directories before updating, and version 1.0.0 removed the page layer type so any component type can be the root, and changed the component registry from a standalone file into a prop. The second is the announcement that UI Builder is now part of BTST, with the description of plugins that generate database schemas, API routes and pages for Next.js, TanStack Start and React Router. That is a change of ownership and direction for a project that had been a standalone open source package, and it is the kind of change that matters to anyone embedding it, because the component you install today is shaped by a commercial platform's roadmap. The release history shows the pace, with 3.5.2 on 2026-02-24, 3.5.3 on 2026-02-25 and 3.6.0 on 2026-07-03, and the last push to the repository was on 2026-07-03. The licence is MIT, the package is TypeScript, and the development workflow in the repository is a set of npm scripts for building the three registries, running the Jest and Playwright test suites, and syncing with the latest shadcn components.

## Conclusion

Adopt ui-builder if your product needs to let non-developers assemble pages from components you already maintain, and if you can accept that the editor is offered through a registry install and a commercial platform that now owns the project. It does not fit a team that wants a general purpose landing page builder or a design tool, because the palette is deliberately limited to your own components, and it does not fit a codebase that cannot adopt shadcn/ui conventions. Before you upgrade across a major version, read the breaking changes section, since v2.0.0 requires deleting the old directories and v1.0.0 changed the component registry into a prop, and confirm that the shadcn registry entry you install matches the shadcn version in your project.

## FAQ

### What is UI Builder and who is it for?

It is a shadcn/ui package that adds a Figma-style editor to your own product, so non-developers can compose pages, emails, dashboards and white-label views using the exact React components you already ship. Layouts are saved as plain JSON for versioning and can be rendered with dynamic data.

### How do I install UI Builder in a shadcn/ui project?

Run the shadcn CLI add command with the block registry URL hosted in the repository, or the init command with a base colour to start a new Next.js project with UI Builder. Two optional registries add the full shadcn component library with 54 pre-configured components and 124 block templates, and the React Email registry.

### What is the componentRegistry in UI Builder?

It is the contract that defines everything the editor can place. Each entry names a React component, a zod schema describing the props the editor may set, and the import path the component came from. You pass it to the editor as a prop, and the built-in primitive definitions can be spread into it as a starting point.

### How do I hide or replace the Tailwind theme panel in UI Builder?

Pass tailwindThemePanel={false} to hide the default TailwindThemePanel in the Appearance tab, or pass your own node such as tailwindThemePanel={<MyCustomThemePanel />} to replace it. Both work without replacing the full panel wiring.

### What breaking changes should I know about before upgrading UI Builder?

Version 2.0.0 changed the internal structure and asks you to delete the old ui-builder and lib/ui-builder directories before updating, and version 1.0.0 removed the page layer type and moved the component registry from a standalone file into a prop. The README also states that UI Builder is now part of BTST.

## Sources

- [License: MIT](https://github.com/olliethedev/ui-builder/blob/main/LICENSE)
- [olliethedev/ui-builder on GitHub](https://github.com/olliethedev/ui-builder)
- [Project website](https://www.uibuilder.app/)
- [README](https://github.com/olliethedev/ui-builder/blob/main/README.md)
- [Releases](https://github.com/olliethedev/ui-builder/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/olliethedev-ui-builder
