DEV Community

Jack Lee
Jack Lee

Posted on • Originally published at blog.crossui.com

Preview and edit material-kit-react without a build step

~7 min read · Tutorial


I look at a lot of MUI admin templates. material-kit-react from the minimals people is one I keep going back to. Clean, typed, and the folder structure makes sense. Repo: minimal-ui-kit/material-kit-react.

But every time I just want to see it, or change one color to check something, it's the same ritual. git clone, npm install, wait, npm run dev, wait more, tab over to localhost. Few minutes gone, a few hundred MB of node_modules on disk. All that to look at a dashboard.

So this time I skipped the build. Opened the folder in CrossUI Studio, rendered src/main.tsx directly. No install, no Vite, no localhost. Below is what I did, including the bits that made me stop and think.

One honest note first. This does not replace your dev server. You still need the real thing for tests, prod builds, actual feature work. It's good for the look-and-tweak loop. Evaluating a template, recoloring something, showing a client. The stuff where booting the whole toolchain costs more than the task itself.


Quick note: local folder support requires a Pro account. To test it out, use the code in the original blog for a free upgrade. No credit card required, available while it lasts.

Your browser does not support video. Watch on YouTube.

1. Clone to local disk (don't open it straight from GitHub)

Studio can mount a GitHub repo directly. For a small repo that's the nicest path. For this one I cloned to disk first:

git clone https://github.com/minimal-ui-kit/material-kit-react
Enter fullscreen mode Exit fullscreen mode

The reason is boring. src/ alone is ~130 files, ~245 in the whole project, spread over sections/, components/, layouts/, theme/, routes/. Opening a project means the tool has to pull the files it touches. Over the GitHub API, on demand, that's a lot of small requests. It works, just not snappy, and you can hit the rate limit if you poke around. A local folder is only the filesystem, so it's instant. For a template this size, local wins.

No npm install here. I only cloned the source. The whole point is to not build.

2. Open the folder — and let it generate a project setting

In Studio: open a Local Folder, pick the cloned material-kit-react directory. It reads the tree. Nothing installs, nothing runs, files stay on my disk. That last part matters if you don't love uploading a client's codebase somewhere just to look at it.

CrossUI Studio — visual IDE for React and MUI

First time in, Studio sees there's no project setting file and pops a prompt:

This project has no CrossUI Studio setting file. We recommend auto-scanning the project to generate one first, then editing it by hand.

CrossUI Studio — visual IDE for React and MUI

Hit Scan & generate. It goes through the project's own config files and writes a setting file at the root. After that, the imports the template uses everywhere just resolve, without Vite in the loop. I didn't have to tell it anything.

CrossUI Studio — visual IDE for React and MUI

You can hand-edit it after. The Project Settings dialog opens right on the generated file. But the auto one was enough for everything below. Couple of seconds, still zero npm install.

3. Open src/main.tsx and hit preview

Close the Project Settings dialog and Studio opens the entry file for you. No need to go hunting in the file tree.

Here's the file you normally can't "just render":

// src/main.tsx
const router = createBrowserRouter([
  {
    Component: () => (
      <App>
        <Outlet />
      </App>
    ),
    errorElement: <ErrorBoundary />,
    children: routesSection,
  },
]);

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <RouterProvider router={router} />
  </StrictMode>
);
Enter fullscreen mode Exit fullscreen mode

This is a Vite entry. createBrowserRouter + RouterProvider, and the whole app lives inside <App> (the theme provider) and routesSection (the routes). Render this file in isolation the naive way and it blows up. No router context, no theme, no #root the way the app wants it.

It rendered anyway. I configured nothing. Opened main.tsx, hit preview, and the dashboard showed up on the canvas with the MUI theme and all.

CrossUI Studio — visual IDE for React and MUI

Now return to the Design Mode. From what I can tell it picks the providers up from the entry files, so a template that does something weird at bootstrap probably needs you to point it at the right one by hand. For material-kit it just worked, and I'd guess it's because app.tsx is this plain:

// src/app.tsx
export default function App({ children }: AppProps) {
  return (
    <ThemeProvider>
      {children}
      {/* github fab */}
    </ThemeProvider>
  );
}
Enter fullscreen mode Exit fullscreen mode

Clean entry files matter a lot here. More on that at the end.

4. Drill down — the providers follow you down (this is the real part)

The dashboard at / isn't one component. It's a lazy-loaded stack:

main.tsx  (RouterProvider defined here + the detected ThemeProvider)
  └─ routesSection              (src/routes/sections.tsx)
       └─ DashboardPage          (src/pages/dashboard.tsx, lazy)
            └─ OverviewAnalyticsView   (src/sections/overview/view)
                 └─ AnalyticsWidgetSummary ×4   (src/sections/overview, the stat cards)
Enter fullscreen mode Exit fullscreen mode

CrossUI Studio — visual IDE for React and MUI

Ctrl+click on the canvas walks you DOWN this tree, one file at a time. The nice surprise: the provider wrapping follows you down by itself. Open the Render Decorations panel at any level and you can see the two wrappers listed, RouterProvider and ThemeProvider:

  • On main.tsx it lists both but auto-skips RouterProvider. Makes sense, that provider lives in this very file, so wrapping again would double it. It only applies the theme.
  • On sections.tsx, then dashboard.tsx, then below, both are on (the panel shows "2"). So router + theme context is there the whole way down. I never had to hand-fix a "missing provider" on the way.

That's usually the painful part of rendering a deep file in isolation, and it was handled for free. What was left on the way to the file I wanted were two small navigation detours. Neither is a crash. They're just what real code looks like.

Detour 1 — sections.tsx opens on the wrong JSX block (renderFallback).

Ctrl+click into the router file and it lands on renderFallback, the Suspense spinner:

// src/routes/sections.tsx
const renderFallback = () => (
  <Box sx={{ display: 'flex', flex: '1 1 auto', alignItems: 'center', justifyContent: 'center' }}>
    ...
  </Box>
);
Enter fullscreen mode Exit fullscreen mode

So the canvas goes almost empty. One file can hold several JSX blocks and this spinner is just the first one. Up top there's a block navigator (the breadcrumb dropdown) listing them all. I jumped to routesSection and its children:

export const routesSection: RouteObject[] = [
  {
    element: ( /* <DashboardLayout><Suspense><Outlet/></Suspense></DashboardLayout> */ ),
    children: [
      { index: true, element: <DashboardPage /> },
      { path: 'user',     element: <UserPage /> },
      { path: 'products', element: <ProductsPage /> },
      { path: 'blog',     element: <BlogPage /> },
    ],
  },
  // sign-in, 404 ...
];
Enter fullscreen mode Exit fullscreen mode

CrossUI Studio — visual IDE for React and MUI

Picked { index: true, element: <DashboardPage /> }, the / route, and the whole dashboard rendered. Theme already riding along from the auto-wrapper. Finding DashboardPage next to UserPage / ProductsPage took one glance. The routes read like the URL map.

CrossUI Studio — visual IDE for React and MUI

Lesson: when a file has more than one JSX block, don't trust the first thing it shows. Use the block navigator to land on the piece you care about.

Detour 2 — index.ts is a barrel, not a component.

From DashboardPage I kept drilling and hit this:

// src/sections/overview/view/index.ts
export * from "./overview-analytics-view.tsx";
Enter fullscreen mode Exit fullscreen mode

CrossUI Studio — visual IDE for React and MUI

NO-TARGET-JSX: No target jsx block found in the file. Which is correct. It's a re-export, there's no JSX to render. sections/ uses these short barrels everywhere so imports stay tidy (from 'src/sections/overview/view' instead of the full path). Click overview-analytics-view.tsx in the file list to open the source file. overview-analytics-view.tsx renders on arrival, theme already applied, and this is the file I actually edit (next section).

So the two things that made me stop weren't errors. The providers rode down on their own. One was a file with multiple JSX blocks (use the navigator), the other a barrel re-export (click through). Half-second detours, and both say more about how the template is wired than about the tool.

CrossUI Studio — visual IDE for React and MUI

(The block navigator above the editor also jumps to any level directly, if clicking through gets old.)

5. Change something

overview-analytics-view.tsx is where the four stat cards get their props, and it reads easy:

<AnalyticsWidgetSummary
  title="Weekly sales"
  percent={2.6}
  total={714000}
  // color defaults to primary
/>
Enter fullscreen mode Exit fullscreen mode

Two small edits, both from the canvas and the inspector. I changed the "Weekly sales" card's color to warning and pushed total up. Then flipped the "New users" card from secondary to success. The diff that lands is exactly that and nothing more:

   <AnalyticsWidgetSummary
     title="Weekly sales"
     percent={2.6}
-    total={714000}
+    total={928000}
+    color="warning"
     ...
   />
   <AnalyticsWidgetSummary
     title="New users"
     percent={-0.1}
     total={1352831}
-    color="secondary"
+    color="success"
     ...
   />
Enter fullscreen mode Exit fullscreen mode

CrossUI Studio — visual IDE for React and MUI

No reformatting, no touched imports, the other cards byte-identical. This is the bit I care about most in these tools. I want to see it write the edit the way I'd have typed it, not re-emit the whole file from some internal model. Here it's a surgical prop change.

If you want a bigger change, the theme is the place. src/theme/ is where the palette gets created, and changing the primary color there recolors buttons, nav, active states, everywhere. Same loop, wider blast radius.

6. Back to the whole app — just hit the browser Back button

Small thing I didn't expect to like this much. I didn't reopen main.tsx from the file tree to get out. Every drill-down step was real navigation, the URL changed each time I stepped in, so the browser Back button walks straight back out. View → page → route → main.tsx. Forward and back behave like any web app. Back a few times and I'm looking at the full dashboard again with my edit baked in. The "Weekly sales" card now amber inside the real layout, not only in the isolated view where I changed it.

CrossUI Studio — visual IDE for React and MUI

That round trip, edit deep in a view then Back all the way out to see it in the whole app, is normally a reload plus a mental context switch. Here it's the same canvas and the Back button.

Total time from git clone to "amber card in the running dashboard": a couple of minutes, most of it the clone. Zero of it npm install.


Why the friction landed where it did (a note for template authors)

It wasn't quite zero friction. Two small navigation detours on the way down. But both were in predictable places, a multi-block router file and a barrel re-export, and each was a one-click fix. A good part of why it was that predictable is the template itself, not the tool. material-kit-react is put together in a way that cooperates:

  • The entry (main.tsx / app.tsx) is straightforward. Providers are right there, not hidden behind three layers of indirection. That's probably why RouterProvider and ThemeProvider got picked up and stayed applied at every level I drilled into. Theme context just rode along, no manual provider fixing on the way down.
  • Routes are lazy() and grouped in routesSection, so the block navigator reads like the URL structure. Spotting DashboardPage next to UserPage / ProductsPage takes one glance.
  • sections/ are split per feature behind short barrel index.ts files. Keeps imports tidy in the real app, and when drilling you just click the one export * line. A predictable pattern beats a clever one.
  • The cards take plain props. AnalyticsWidgetSummary is just title/total/percent/color/chart, fed by the view. So editing one from the view is a data change, not a backend call, and the diff stays a single line.

A messier template would be harder to preview this way, tool or no tool. Providers assembled dynamically, one 2000-line page, sections that only work when fed real fetched data. So good template structure is a big part of what makes "open it without building it" realistic. Hats off to material-kit-react there, the structure is doing real work.

The practical upshot, if you make or sell templates. A chunk of the friction for someone evaluating your template is the clone-install-run tax before they see anything. Being previewable and tweakable straight from source cuts that tax a lot. Worth thinking about.

What I would not use it for

  • Running the test suite or the real Vite build. This is preview + edit, not CI.
  • Anything that needs live backend data to render at all. You can mock it for a drill-down, but that's a different workflow.
  • A final answer on runtime behavior. It renders structure from the source. It's not watching your app actually execute end to end.

For "open this template, change a couple of things, see it in context", which is most of what I do with admin kits before committing to one, skipping the build was just less ceremony.


Quick note: local folder support requires a Pro account. To test it out, use the code in the original blog for a free upgrade. No credit card required, available while it lasts.

Top comments (0)