For AI agents: the complete documentation index is available at https://mfeflow.github.io/mfeflow/llms.txt, the full documentation bundle is available at https://mfeflow.github.io/mfeflow/llms-full.txt, and this page is available as Markdown at https://mfeflow.github.io/mfeflow/features/ui-shadcn.md.

ui-shadcn

shadcn/ui gives you components as source files rather than a package. This feature sets that up in each remote on top of the Tailwind prefix, so the components carry the right class names and read the same theme as the rest of the page.

What you get

Every remote gets its own copy of a Button, a class helper called cn and a shadcn config. Nothing is shared between remotes. A button in one remote and a button in another are two files that look the same because they read the same theme tokens.

Add it

ui-shadcn needs tailwind. Add both in one command, or add tailwind first. Without it, add stops with E206.

pnpm mfeflow add tailwind ui-shadcn

What changed, in every remote:

components.json          # shadcn's config, with the remote's css path and prefix
src/
├── lib/
│   └── utils.ts         # the cn helper
└── components/ui/
    └── button.tsx       # the Button

Each of the last two files also gets a test if you use testing. Three packages are added as dependencies:

class-variance-authority
clsx
tailwind-merge

Use it

Import the button from the remote's own folder and use it like any component.

import { Button } from './components/ui/button';

<Button variant="outline" size="sm" onClick={save}>
  Save
</Button>;

The files are yours to change or delete. This is the start of the generated button, where every class carries the remote's prefix (cart here).

apps/cart/src/components/ui/button.tsx
variant: {
  default: 'cart:bg-primary cart:text-primary-foreground cart:hover:opacity-90',
  secondary: 'cart:bg-secondary cart:text-secondary-foreground cart:hover:opacity-80',
  outline: 'cart:border cart:border-border cart:bg-background cart:hover:bg-accent cart:hover:text-accent-foreground',
  destructive: 'cart:bg-destructive cart:text-white cart:hover:opacity-90',
  ghost: 'cart:hover:bg-accent cart:hover:text-accent-foreground',
},

Configure it

There are no install options. These are the knobs you will actually reach for.

SettingWhereValues
variantButton propdefault, secondary, outline, destructive, ghost
sizeButton propdefault, sm, lg
typeButton propbutton unless you pass submit, so it never submits a form by accident
stylecomponents.jsonnew-york
baseColorcomponents.jsonneutral
prefixcomponents.jsonthis remote's Tailwind prefix
iconLibrarycomponents.jsonlucide

How it works

cn joins class names with clsx, then merges them with tailwind-merge, which is told about the remote's prefix. That is why this keeps only the last padding class:

cn('cart:p-2', 'cart:p-4'); // 'cart:p-4'

The colours come from the tokens the tailwind feature defines. Those read the --mf-* variables, so with theming a theme switch recolours every remote's buttons together.

The three helper libraries only reach a remote's bundle when something imports them. Nothing uses the Button yet, so a remote that does not use it pays nothing. Watch the default 10 KB remote budget when you start using it.

Gotchas

  • To add more components with the shadcn CLI, first give the remote the @/ alias it expects. Add this to the remote's tsconfig.json under compilerOptions, and Rsbuild reads it from there.

    "baseUrl": ".",
    "paths": { "@/*": ["./src/*"] }
  • Then run the CLI from the remote's folder. It adds the prefix to the classes it writes, because of "prefix" in components.json.

    cd apps/cart
    pnpm dlx shadcn@latest add dialog
  • Check one new component after adding it. This Button leaves out shadcn's asChild and Radix Slot, so the remote has no Radix dependency until you add a component that needs one.

Reference