<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jack Lee</title>
    <description>The latest articles on DEV Community by Jack Lee (@linb).</description>
    <link>https://dev.to/linb</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F167185%2Fa03d48fd-2235-4fef-aa0a-9f5a2b9ea784.jpeg</url>
      <title>DEV Community: Jack Lee</title>
      <link>https://dev.to/linb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/linb"/>
    <language>en</language>
    <item>
      <title>What if students could edit a real React app before they can even write one?</title>
      <dc:creator>Jack Lee</dc:creator>
      <pubDate>Mon, 03 Aug 2026 12:01:00 +0000</pubDate>
      <link>https://dev.to/linb/what-if-students-could-edit-a-real-react-app-before-they-can-even-write-one-13n2</link>
      <guid>https://dev.to/linb/what-if-students-could-edit-a-real-react-app-before-they-can-even-write-one-13n2</guid>
      <description>&lt;p&gt;Most React courses teach in the same order. Syntax first. Then hooks. Then a small app. Then, somewhere near the end — if there's time — how a real project is actually organized.&lt;/p&gt;

&lt;p&gt;I understand why. You can't explain a provider tree to someone who doesn't know what a component is. The order makes sense on paper.&lt;/p&gt;

&lt;p&gt;But there's a gap in the middle that nobody really covers, and I think it's the reason so many people finish a course and still feel like they can't read real code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading code and understanding code are different things
&lt;/h2&gt;

&lt;p&gt;You can stare at this for an hour:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AnalyticsWidgetSummary&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Weekly sales"&lt;/span&gt;
  &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;714000&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"warning"&lt;/span&gt;
  &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;series&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;82&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;84&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;77&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you'll "understand" it. Title is a string. Total is a number. Color is a string that's probably one of a few allowed values. Chart is an object with a series array.&lt;/p&gt;

&lt;p&gt;Now: what does &lt;code&gt;color="warning"&lt;/code&gt; actually change? Where does "warning" come from? Is it defined in this file? No. In the component? No. It's in a theme object, three directories away, that gets injected through a provider wrapped around the entire app in a file the student has never opened.&lt;/p&gt;

&lt;p&gt;None of that is visible from reading the line. You only learn it by changing the value and watching what happens — or better, by changing the &lt;em&gt;theme&lt;/em&gt; and watching six unrelated components shift at once. That's the moment the concept lands. Not before.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sandboxes solve the setup problem, not the structure problem
&lt;/h2&gt;

&lt;p&gt;The usual answer here is CodeSandbox or StackBlitz, and they're genuinely good tools. Setup friction goes to zero, the student clicks a link and there's running code. Great.&lt;/p&gt;

&lt;p&gt;But look at what's actually in most educational sandboxes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One file, maybe three&lt;/li&gt;
&lt;li&gt;No routing&lt;/li&gt;
&lt;li&gt;No theme provider&lt;/li&gt;
&lt;li&gt;No barrel exports&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;features/&lt;/code&gt; folder, no &lt;code&gt;layouts/&lt;/code&gt;, no shared component library&lt;/li&gt;
&lt;li&gt;State that lives exactly where you'd expect it to live&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's a curated environment. It's useful for isolating one concept — and that's what it's for — but it's the opposite of what the student will face at their first job. Real apps are five providers deep before anything renders. Components import from &lt;code&gt;@/components&lt;/code&gt; which re-exports from somewhere else which re-exports from somewhere else. Half the props come from a context you can't see in the file you're looking at.&lt;/p&gt;

&lt;p&gt;So we teach on tidy code and then hand people messy code and act surprised when the transition is rough.&lt;/p&gt;

&lt;h2&gt;
  
  
  The missing link: code and canvas, pointing at each other
&lt;/h2&gt;

&lt;p&gt;There's one more thing sandboxes structurally can't do, and I think it matters more for learning than anything else on this list.&lt;/p&gt;

&lt;p&gt;In a sandbox, the editor and the preview are two separate worlds. You have code on the left, a rendered iframe on the right, and nothing connects them. If a student sees a card on screen and wants to know which JSX made it, they have to guess: search for the text, scroll, open three files, guess again. If they change a line of code, they see &lt;em&gt;something&lt;/em&gt; change on the right, but they have to work out for themselves which change was theirs.&lt;/p&gt;

&lt;p&gt;That guessing step is where beginners lose the thread. It's a translation tax paid on every single interaction.&lt;/p&gt;

&lt;p&gt;Now flip it. Selection is shared in both directions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Click a JSX node in the code, the matching element lights up on the canvas.&lt;/strong&gt; "This is what that line draws." No searching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Click an element or prop on the canvas, the exact JSX node or prop gets selected and highlighted in the code.&lt;/strong&gt; “That’s the line that made this — and the property that controls it.” No guessing..&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And editing works both ways too:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Type in the code, the canvas updates live.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Change a prop on the canvas, and the corresponding code updates — the changed prop briefly highlights.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sounds small. It isn't. What it does is collapse the gap between &lt;em&gt;symbol&lt;/em&gt; and &lt;em&gt;thing&lt;/em&gt;. Beginners spend enormous energy holding an unstable mental map between "this text" and "that rectangle on screen." When the tool holds the map for them, that energy goes back into the actual concept.&lt;/p&gt;

&lt;p&gt;It's the same reason browser devtools were such a leap for learning CSS. Before devtools you edited a stylesheet and reloaded and squinted. After devtools, you clicked the element and &lt;em&gt;saw&lt;/em&gt; which rules applied. Nobody argues devtools made people worse at CSS. It just removed the guessing.&lt;/p&gt;

&lt;p&gt;React never really got that moment. The component tree is a runtime construct, the JSX is source text, and the two have historically lived in separate windows with no line between them. Two-way selection is that line.&lt;/p&gt;

&lt;p&gt;And this genuinely is not something CodeSandbox or StackBlitz can bolt on. They run your code in an iframe — they can host it and hot-reload it, but they don't have a live mapping from the rendered DOM node back to the exact AST node that produced it, especially once that node came out of a &lt;code&gt;.map()&lt;/code&gt;, or a ternary, or a component defined in a different file. That mapping is the hard part, and it's the part that turns "here's your code running" into "here's your code, and here's what each piece of it is."&lt;/p&gt;

&lt;p&gt;For a student, the practical effect is that the feedback loop drops from minutes to zero. Click, see, change, see. Repeat forty times in a session. That's not a nicer UI — that's a different learning rate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The dependency graph is the thing you're actually teaching
&lt;/h2&gt;

&lt;p&gt;Here's the part I think gets underrated. When a student says "I can't find where this comes from," they're not asking a syntax question. They're asking a &lt;em&gt;graph&lt;/em&gt; question.&lt;/p&gt;

&lt;p&gt;Every React codebase is a dependency graph. Files import files, barrels re-export barrels, a component pulls a hook that pulls a context that's provided six levels up. The rendered UI is just one projection of that graph. Most of the confusion beginners have — "where does this prop come from," "why did changing that file break this screen," "which of these five &lt;code&gt;index.ts&lt;/code&gt; files is the real one" — is them trying to traverse a graph they can't see.&lt;/p&gt;

&lt;p&gt;Courses teach the tree (component hierarchy). They mostly skip the graph (module dependencies). But the graph is what you navigate every day at work.&lt;/p&gt;

&lt;p&gt;So the exercise gets better if you make the graph visible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trace one import chain end to end.&lt;/strong&gt; &lt;code&gt;AnalyticsWidgetSummary&lt;/code&gt; → &lt;code&gt;@/components/chart&lt;/code&gt; → &lt;code&gt;chart/index.ts&lt;/code&gt; → &lt;code&gt;chart-widget.tsx&lt;/code&gt;. Three re-exports to get to real code. That's not unusual; that's Tuesday.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask "what breaks if I delete this file?"&lt;/strong&gt; and then actually look at the answer. Inbound edges are a concept you can feel, not just define.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Show a broken edge.&lt;/strong&gt; Rename an export and watch which parts of the graph go red. Beginners learn far more from a targeted break than from a working example.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's a practical angle too: real templates often have edges that don't resolve — a missing peer dep, an optional import, a path alias nobody configured. Traditionally that's a hard stop; nothing renders, the student is dead in the water in minute three. It doesn't have to be. If the tool can bypass an unresolved import and keep rendering the rest of the graph, a broken edge becomes a lesson instead of a blocker. (We wrote about the mechanics of that separately, in &lt;a href="https://blog.crossui.com/2026/06/dont-just-find-the-broken-import-bypass-it" rel="noopener noreferrer"&gt;Don't just find the broken import. Bypass it.&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;A student who can read a dependency graph can onboard onto any codebase. A student who only knows hooks can onboard onto the one they were taught.&lt;/p&gt;

&lt;h2&gt;
  
  
  The thing that's usually a diagram
&lt;/h2&gt;

&lt;p&gt;Every React curriculum I've seen has a moment where the instructor draws a box, puts smaller boxes inside it, and says "so the provider wraps everything, and the components underneath can read from it."&lt;/p&gt;

&lt;p&gt;The diagram is correct. It's also inert. It doesn't respond when you poke it. Nobody has ever learned what a provider does by looking at a rectangle.&lt;/p&gt;

&lt;p&gt;What if instead of the diagram, the student opened the actual app — a real, shipped, slightly messy admin template — clicked into a card buried four levels deep inside a &lt;code&gt;.map()&lt;/code&gt; inside a conditional inside a layout component, and changed one prop? And saw both the rendered result and the exact source diff at the same time?&lt;/p&gt;

&lt;p&gt;That's not a replacement for the explanation. It's the thing the explanation is &lt;em&gt;about&lt;/em&gt;, made touchable.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this actually looks like in practice
&lt;/h2&gt;

&lt;p&gt;Concretely, here's the exercise I keep imagining for week one, before the student has written a single line of React themselves:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Open a real template.&lt;/strong&gt; Not a teaching example — something that actually shipped. Material Kit React, shadcn-admin, whatever. Entry file, straight from disk. No &lt;code&gt;npm install&lt;/code&gt;, no dev server, no "wait for it to build."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Find one thing on screen.&lt;/strong&gt; "See that revenue card in the top left? Click it." The corresponding JSX highlights in the code — they didn't search for it, they pointed at it. Then walk back up: &lt;code&gt;main.tsx&lt;/code&gt; → &lt;code&gt;DashboardPage&lt;/code&gt; → &lt;code&gt;OverviewAnalyticsView&lt;/code&gt; → &lt;code&gt;AnalyticsWidgetSummary&lt;/code&gt;. Four hops. The student just learned what a component tree is, by walking one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.5. Go the other direction.&lt;/strong&gt; Put the cursor on a random JSX node in the code and watch the canvas highlight what it draws. Do it on a node inside a &lt;code&gt;.map()&lt;/code&gt; so they see one line of code producing eight things on screen. That single observation explains lists better than any lecture on &lt;code&gt;key&lt;/code&gt; props.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Change one prop — from both sides.&lt;/strong&gt; Edit &lt;code&gt;total={714000}&lt;/code&gt; → &lt;code&gt;total={928000}&lt;/code&gt; in the code, watch the number change. Then change the next card's value on the canvas instead, and watch the one-line diff appear in the source. Same operation, two directions. That's props, and that's also the first time most students really believe the UI &lt;em&gt;is&lt;/em&gt; the code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.5. Follow one import out of the file.&lt;/strong&gt; Where does &lt;code&gt;AnalyticsWidgetSummary&lt;/code&gt; actually live? Not the import line — the real file, past the barrels. Two or three hops through the dependency graph. Do it once by hand so they know what the tool is doing for them later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Change something in the theme.&lt;/strong&gt; Watch six other components move. That's context. No diagram required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Break something on purpose.&lt;/strong&gt; Pass a string where a number goes. See what React does. Fix it.&lt;/p&gt;

&lt;p&gt;None of that requires the student to know how to write React yet. It requires them to know how to &lt;em&gt;read&lt;/em&gt; it and &lt;em&gt;poke&lt;/em&gt; it — which is honestly what most junior work is anyway. You're rarely writing a new app from scratch. You're finding the thing in someone else's codebase and changing it without breaking three other things.&lt;/p&gt;

&lt;h2&gt;
  
  
  The objection I keep coming back to
&lt;/h2&gt;

&lt;p&gt;The obvious pushback: isn't this just teaching people to be dependent on a visual tool? If they can't find the file by hand, have they actually learned anything?&lt;/p&gt;

&lt;p&gt;I think that's a fair worry, and it depends entirely on how it's used. If the tool does the navigation &lt;em&gt;for&lt;/em&gt; them and they never look at the path, no, they haven't learned much. If the tool shows them the path — literally, the breadcrumb of components it walked through, and the file each one lives in — then it's closer to training wheels than a crutch. They see the structure repeatedly, in a real codebase, until it stops being mysterious.&lt;/p&gt;

&lt;p&gt;The other objection: real templates are messy, and messy is confusing for beginners. Also fair. But they're going to hit messy eventually, and I'd rather they hit it with an instructor in the room than alone on day three of a new job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I'm thinking about this at all
&lt;/h2&gt;

&lt;p&gt;I build a tool that does the "open a real React app with no build step and edit it" part — &lt;a href="https://studio.crossui.com" rel="noopener noreferrer"&gt;CrossUI Studio&lt;/a&gt;. It wasn't built for education. It was built because I got tired of running &lt;code&gt;npm install&lt;/code&gt; on a template just to see whether the card component was worth using.&lt;/p&gt;

&lt;p&gt;But the education angle keeps coming up. People teaching React tell me the hardest part isn't syntax — it's the gap between "I can write a component" and "I can find my way around a codebase someone else wrote." That gap is not a knowledge problem. You can't lecture it away. It's a familiarity problem, and familiarity comes from time spent poking at real things.&lt;/p&gt;

&lt;p&gt;So the question I actually want to ask: &lt;strong&gt;has anyone teaching React tried starting with a real app instead of a curated one?&lt;/strong&gt; Bootcamps, university courses, even internal onboarding for new hires. Did it work? Did students find it empowering, or just overwhelming? Is there a reason this is a bad idea that I'm not seeing from where I sit?&lt;/p&gt;

&lt;p&gt;Genuinely curious. I'm on the tool side of this, not the teaching side, and I'd rather hear from people who've actually stood in front of a room of beginners.&lt;/p&gt;




&lt;p&gt;If you want to try the mechanic yourself: &lt;a href="https://studio.crossui.com" rel="noopener noreferrer"&gt;Guest mode&lt;/a&gt; opens instantly, no account. Point it at a template, click something, and see how far down it goes.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>javascript</category>
      <category>learning</category>
      <category>react</category>
    </item>
    <item>
      <title>Preview and edit material-kit-react without a build step</title>
      <dc:creator>Jack Lee</dc:creator>
      <pubDate>Thu, 23 Jul 2026 18:52:02 +0000</pubDate>
      <link>https://dev.to/linb/preview-and-edit-material-kit-react-without-a-build-step-1hc9</link>
      <guid>https://dev.to/linb/preview-and-edit-material-kit-react-without-a-build-step-1hc9</guid>
      <description>&lt;p&gt;&lt;em&gt;~7 min read · Tutorial&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I look at a lot of MUI admin templates. &lt;code&gt;material-kit-react&lt;/code&gt; from the minimals people is one I keep going back to. Clean, typed, and the folder structure makes sense. Repo: &lt;a href="https://github.com/minimal-ui-kit/material-kit-react" rel="noopener noreferrer"&gt;minimal-ui-kit/material-kit-react&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;So this time I skipped the build. Opened the folder in &lt;a href="https://stuido.crossui.com/app" rel="noopener noreferrer"&gt;CrossUI Studio&lt;/a&gt;, rendered &lt;code&gt;src/main.tsx&lt;/code&gt; directly. No install, no Vite, no localhost. Below is what I did, including the bits that made me stop and think.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Quick note&lt;/strong&gt;: 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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your browser does not support video. Watch on &lt;a href="https://youtu.be/Oesi3dvXHoQ" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  1. Clone to local disk (don't open it straight from GitHub)
&lt;/h2&gt;

&lt;p&gt;Studio can mount a GitHub repo directly. For a small repo that's the nicest path. For this one I cloned to disk first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/minimal-ui-kit/material-kit-react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reason is boring. &lt;code&gt;src/&lt;/code&gt; alone is ~130 files, ~245 in the whole project, spread over &lt;code&gt;sections/&lt;/code&gt;, &lt;code&gt;components/&lt;/code&gt;, &lt;code&gt;layouts/&lt;/code&gt;, &lt;code&gt;theme/&lt;/code&gt;, &lt;code&gt;routes/&lt;/code&gt;. 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.&lt;/p&gt;

&lt;p&gt;No &lt;code&gt;npm install&lt;/code&gt; here. I only cloned the source. The whole point is to not build.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Open the folder — and let it generate a project setting
&lt;/h2&gt;

&lt;p&gt;In Studio: open a &lt;strong&gt;Local Folder&lt;/strong&gt;, pick the cloned &lt;code&gt;material-kit-react&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-0.png" alt="CrossUI Studio — visual IDE for React and MUI" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First time in, Studio sees there's no project setting file and pops a prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This project has no CrossUI Studio setting file. We recommend auto-scanning the project to generate one first, then editing it by hand.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-1.png" alt="CrossUI Studio — visual IDE for React and MUI" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hit &lt;strong&gt;Scan &amp;amp; generate&lt;/strong&gt;. 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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-2.png" alt="CrossUI Studio — visual IDE for React and MUI" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;npm install&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Open &lt;code&gt;src/main.tsx&lt;/code&gt; and hit preview
&lt;/h2&gt;

&lt;p&gt;Close the Project Settings dialog and Studio opens the entry file for you. No need to go hunting in the file tree.&lt;/p&gt;

&lt;p&gt;Here's the file you normally can't "just render":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/main.tsx&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createBrowserRouter&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Outlet&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;errorElement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ErrorBoundary&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt;
    &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;routesSection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RouterProvider&lt;/span&gt; &lt;span class="na"&gt;router&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;It rendered anyway. I configured nothing. Opened &lt;code&gt;main.tsx&lt;/code&gt;, hit preview, and the dashboard showed up on the canvas with the MUI theme and all.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-21.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-21.png" alt="CrossUI Studio — visual IDE for React and MUI" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;app.tsx&lt;/code&gt; is this plain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/app.tsx&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;AppProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ThemeProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* github fab */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ThemeProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean entry files matter a lot here. More on that at the end.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Drill down — the providers follow you down (this is the real part)
&lt;/h2&gt;

&lt;p&gt;The dashboard at &lt;code&gt;/&lt;/code&gt; isn't one component. It's a lazy-loaded stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-3.png" alt="CrossUI Studio — visual IDE for React and MUI" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;On &lt;code&gt;main.tsx&lt;/code&gt; it lists both but &lt;em&gt;auto-skips&lt;/em&gt; &lt;code&gt;RouterProvider&lt;/code&gt;. Makes sense, that provider lives in this very file, so wrapping again would double it. It only applies the theme.&lt;/li&gt;
&lt;li&gt;On &lt;code&gt;sections.tsx&lt;/code&gt;, then &lt;code&gt;dashboard.tsx&lt;/code&gt;, 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.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Detour 1 — &lt;code&gt;sections.tsx&lt;/code&gt; opens on the wrong JSX block (&lt;code&gt;renderFallback&lt;/code&gt;).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ctrl+click into the router file and it lands on &lt;code&gt;renderFallback&lt;/code&gt;, the Suspense spinner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/routes/sections.tsx&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;renderFallback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt; &lt;span class="na"&gt;sx&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1 1 auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;alignItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;justifyContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    ...
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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 &lt;code&gt;routesSection&lt;/code&gt; and its children:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routesSection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RouteObject&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="cm"&gt;/* &amp;lt;DashboardLayout&amp;gt;&amp;lt;Suspense&amp;gt;&amp;lt;Outlet/&amp;gt;&amp;lt;/Suspense&amp;gt;&amp;lt;/DashboardLayout&amp;gt; */&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DashboardPage&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserPage&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProductsPage&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BlogPage&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// sign-in, 404 ...&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-4.png" alt="CrossUI Studio — visual IDE for React and MUI" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-5.png" alt="CrossUI Studio — visual IDE for React and MUI" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Detour 2 — &lt;code&gt;index.ts&lt;/code&gt; is a barrel, not a component.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From &lt;code&gt;DashboardPage&lt;/code&gt; I kept drilling and hit this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/sections/overview/view/index.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./overview-analytics-view.tsx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-6.png" alt="CrossUI Studio — visual IDE for React and MUI" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-7.png" alt="CrossUI Studio — visual IDE for React and MUI" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(The block navigator above the editor also jumps to any level directly, if clicking through gets old.)&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Change something
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;overview-analytics-view.tsx&lt;/code&gt; is where the four stat cards get their props, and it reads easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AnalyticsWidgetSummary&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Weekly sales"&lt;/span&gt;
  &lt;span class="na"&gt;percent&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;2.6&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;714000&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// color defaults to primary&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;   &amp;lt;AnalyticsWidgetSummary
     title="Weekly sales"
     percent={2.6}
&lt;span class="gd"&gt;-    total={714000}
&lt;/span&gt;&lt;span class="gi"&gt;+    total={928000}
+    color="warning"
&lt;/span&gt;     ...
   /&amp;gt;
   &amp;lt;AnalyticsWidgetSummary
     title="New users"
     percent={-0.1}
     total={1352831}
&lt;span class="gd"&gt;-    color="secondary"
&lt;/span&gt;&lt;span class="gi"&gt;+    color="success"
&lt;/span&gt;     ...
   /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-7.png" alt="CrossUI Studio — visual IDE for React and MUI" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  6. Back to the whole app — just hit the browser Back button
&lt;/h2&gt;

&lt;p&gt;Small thing I didn't expect to like this much. I didn't reopen &lt;code&gt;main.tsx&lt;/code&gt; from the file tree to get out. Every drill-down step was real navigation, the URL changed each time I stepped in, so the &lt;strong&gt;browser Back button walks straight back out&lt;/strong&gt;. View → page → route → &lt;code&gt;main.tsx&lt;/code&gt;. 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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fpreview-edit-tpl-without-build-8.png" alt="CrossUI Studio — visual IDE for React and MUI" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Total time from &lt;code&gt;git clone&lt;/code&gt; to "amber card in the running dashboard": a couple of minutes, most of it the clone. Zero of it &lt;code&gt;npm install&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the friction landed where it did (a note for template authors)
&lt;/h2&gt;

&lt;p&gt;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. &lt;code&gt;material-kit-react&lt;/code&gt; is put together in a way that cooperates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The entry (&lt;code&gt;main.tsx&lt;/code&gt; / &lt;code&gt;app.tsx&lt;/code&gt;) is straightforward. Providers are right there, not hidden behind three layers of indirection. That's probably why &lt;code&gt;RouterProvider&lt;/code&gt; and &lt;code&gt;ThemeProvider&lt;/code&gt; 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.&lt;/li&gt;
&lt;li&gt;Routes are &lt;code&gt;lazy()&lt;/code&gt; and grouped in &lt;code&gt;routesSection&lt;/code&gt;, so the block navigator reads like the URL structure. Spotting &lt;code&gt;DashboardPage&lt;/code&gt; next to &lt;code&gt;UserPage&lt;/code&gt; / &lt;code&gt;ProductsPage&lt;/code&gt; takes one glance.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sections/&lt;/code&gt; are split per feature behind short barrel &lt;code&gt;index.ts&lt;/code&gt; files. Keeps imports tidy in the real app, and when drilling you just click the one &lt;code&gt;export *&lt;/code&gt; line. A predictable pattern beats a clever one.&lt;/li&gt;
&lt;li&gt;The cards take &lt;strong&gt;plain props&lt;/strong&gt;. &lt;code&gt;AnalyticsWidgetSummary&lt;/code&gt; is just &lt;code&gt;title/total/percent/color/chart&lt;/code&gt;, 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.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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 &lt;strong&gt;material-kit-react&lt;/strong&gt; there, the structure is doing real work.&lt;/p&gt;

&lt;p&gt;The practical upshot, if you make or sell templates. A chunk of the friction for someone &lt;em&gt;evaluating&lt;/em&gt; 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.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would not use it for
&lt;/h2&gt;

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

&lt;p&gt;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.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Quick note&lt;/strong&gt;: 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.&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactjsdevelopment</category>
      <category>mui</category>
      <category>development</category>
    </item>
    <item>
      <title>Editing React components that never rendered</title>
      <dc:creator>Jack Lee</dc:creator>
      <pubDate>Mon, 13 Jul 2026 14:33:47 +0000</pubDate>
      <link>https://dev.to/linb/editing-react-components-that-never-rendered-3dol</link>
      <guid>https://dev.to/linb/editing-react-components-that-never-rendered-3dol</guid>
      <description>&lt;p&gt;&lt;em&gt;~7 min read · Engineering&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There are only two ways a tool can learn the shape of your React code. Which one you pick decides the single most important thing about the tool: whether it's available in the exact moment you need it most.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two ways to know a codebase
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Runtime introspection&lt;/strong&gt; watches a running app. React DevTools, profilers, error overlays — they read the live fiber tree after the app mounts. This is the richer of the two: they know real prop values, real state, what actually rendered. But all of that is conditional on one thing — the app has to successfully run first. The moment a render throws, they go dark. Nothing mounted, so there's nothing to inspect. And a module that failed to initialize is invisible to them by definition.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Static AST analysis&lt;/strong&gt; reads source. It parses each file into an abstract syntax tree and reads the structure directly — every JSX node, every import, every prop — without executing anything. It's poorer in one sense: it can't tell you what a variable held at 2:04pm, because nothing ran. But it has a property no runtime tool can match: it works on code that has never once rendered cleanly.&lt;/p&gt;

&lt;p&gt;Most developer tooling is built on the first model. We built CrossUI Studio — a visual editor for React — on the second, on purpose. This post is about why that constraint turned out to be the whole point.&lt;/p&gt;

&lt;h2&gt;
  
  
  The moment tooling abandons you
&lt;/h2&gt;

&lt;p&gt;Here's the scenario that shaped the decision. A component renders blank. The stack trace points at the component, but the real failure is five imports down — a dynamic import that didn't resolve, a peer dependency that got bumped, a circular reference that's &lt;code&gt;undefined&lt;/code&gt; on first access. The component is innocent; the thing it transitively pulls in is the culprit.&lt;/p&gt;

&lt;p&gt;This is exactly when you most need to understand your code's structure — which file imports what, where the break is, what the surrounding code looks like. And it's exactly when every runtime tool has gone dark, because the app didn't render. DevTools shows nothing. The profiler has no render to profile. The error overlay gives you a line number but not the shape of the code around it. They all need the app to run first, and the entire problem is that it won't.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The one moment you most need to see your code's structure is the one moment a runtime tool refuses to produce it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A static AST tool has no such dependency. It parsed the files when you opened them; it can draw the whole import graph, point at the broken module, and show you the code around it — with the app fully crashed. A broken page isn't a dead end. It's the entry point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Editing what you can't run
&lt;/h2&gt;

&lt;p&gt;The same property unlocks something stranger: editing a component that isn't rendering, in a file you never opened.&lt;/p&gt;

&lt;p&gt;Think about what a visual editor normally needs to render a &lt;code&gt;&amp;lt;Card&amp;gt;&lt;/code&gt; that lives inside a &lt;code&gt;.map()&lt;/code&gt;. To put that Card on a canvas, it has to know what &lt;code&gt;item&lt;/code&gt; is — and &lt;code&gt;item&lt;/code&gt; only exists at runtime, inside the loop, when real data flows through. A runtime-based editor simply can't render that Card in isolation; there's no live &lt;code&gt;item&lt;/code&gt; to feed it. So most visual editors quietly refuse to go inside a &lt;code&gt;.map()&lt;/code&gt; at all.&lt;/p&gt;

&lt;p&gt;Working from the AST, the problem reframes. We don't need a running loop; we need the &lt;em&gt;node&lt;/em&gt;. Parse the file, find the JSX inside the map callback, and render that subtree in isolation. The one thing missing is the value of &lt;code&gt;item&lt;/code&gt; — so we ask you for it (a small mock in a panel) rather than requiring the app to produce it. The Card renders, live, with real theming, standing on its own.&lt;/p&gt;

&lt;p&gt;And because the unit of understanding is the AST node rather than the mounted component, drill-down doesn't stop at the file boundary. A child component imported from another file is just another edge in the graph. Follow the import, parse that file, render its node — you're editing a component defined somewhere you never opened, in an app that may never have rendered as a whole.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cost of the constraint
&lt;/h2&gt;

&lt;p&gt;None of this is free, and pretending otherwise would be dishonest. Static analysis buys unconditional availability by giving up runtime knowledge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fully dynamic imports are unresolvable.&lt;/strong&gt; &lt;code&gt;import('./pages/' + name)&lt;/code&gt; with a runtime-computed path can't be resolved statically. We mark the edge rather than guess.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;We see structure, not values.&lt;/strong&gt; The AST tells you &lt;code&gt;AIPanel&lt;/code&gt; reaches &lt;code&gt;TreeSitter&lt;/code&gt;; it can't tell you what the parser returned on a given render. Mock data stands in for real data; it doesn't replay it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exotic resolution needs config.&lt;/strong&gt; Non-standard bundler aliases or monorepo path magic resolve best when we can read your tsconfig/jsconfig. Without it, some edges fall back to raw specifiers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are real boundaries. But notice none of them touch the core promise: the tool is &lt;em&gt;there&lt;/em&gt; when you're stuck, because it never needed your code to run in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is one idea, not many
&lt;/h2&gt;

&lt;p&gt;The crash-surviving dependency graph, the edit-inside-a-map drill-down, the cross-file navigation, the one-line diffs — from the outside they look like separate features. They're the same decision seen from different angles: &lt;strong&gt;treat parsed source as the source of truth, and make every surface a view over that AST.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The canvas is a view over the AST. The prop inspector is a view over the AST. The dependency graph is a view over the AST across files. None of them depend on a successful render, because none of them are built on the runtime. That's a harder thing to build than hooking the fiber tree — and it's exactly what keeps the tooling alive in the moments the runtime, and everything built on it, goes dark.&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://studio.crossui.com" rel="noopener noreferrer"&gt;Try it&lt;/a&gt; — open a project, break a deep import on purpose, and watch the structure still render.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About CrossUI Studio&lt;/strong&gt; — A visual IDE for React &amp;amp; MUI. Code and canvas stay in two-way sync on the same AST: edit code and the canvas updates live; click an element on the canvas, edit its props visually, and the code changes with a surgical one-line diff. No build, no localhost — it runs in the browser, works on your real Git repo or a local folder, with no vendor lock-in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://studio.crossui.com" rel="noopener noreferrer"&gt;Try it free → studio.crossui.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>development</category>
    </item>
    <item>
      <title>Edit inside a .map(), a ternary, even a component in another file</title>
      <dc:creator>Jack Lee</dc:creator>
      <pubDate>Mon, 06 Jul 2026 13:07:34 +0000</pubDate>
      <link>https://dev.to/linb/edit-inside-a-map-a-ternary-even-a-component-in-another-file-2e7</link>
      <guid>https://dev.to/linb/edit-inside-a-map-a-ternary-even-a-component-in-another-file-2e7</guid>
      <description>&lt;p&gt;&lt;em&gt;~7 min read · Tutorial&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's the wall almost every visual editor hits. You can edit the outer JSX just fine. But the thing you actually need to change is a &lt;code&gt;Card&lt;/code&gt; &lt;em&gt;inside&lt;/em&gt; a &lt;code&gt;.map()&lt;/code&gt;, and the tool goes quiet — because to render that &lt;code&gt;Card&lt;/code&gt;, it needs to know what &lt;code&gt;item&lt;/code&gt; is, and &lt;code&gt;item&lt;/code&gt; only exists at runtime, inside the callback.&lt;/p&gt;

&lt;p&gt;So you drop back to hand-editing. Which is fine, except the whole reason you opened a visual editor was to not do that.&lt;/p&gt;

&lt;p&gt;CrossUI Studio's Layer Drill-down Engine is built for exactly this. You can isolate and edit &lt;em&gt;any&lt;/em&gt; node at &lt;em&gt;any&lt;/em&gt; depth — including the ones that live behind a runtime boundary. And drill-down doesn't stop at the file edge: &lt;strong&gt;Ctrl+click a child component and Studio follows it into the file where it's defined&lt;/strong&gt;, keeping the canvas live the whole way down.&lt;/p&gt;

&lt;h2&gt;
  
  
  The depth problem, concretely
&lt;/h2&gt;

&lt;p&gt;Take a list that every React app has some version of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;elevation&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;featured&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CardContent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Typography&lt;/span&gt; &lt;span class="na"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"h6"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Typography&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Chip&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"small"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;CardContent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;))}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You want to visually tweak that &lt;code&gt;Card&lt;/code&gt; — bump the padding, change the &lt;code&gt;Chip&lt;/code&gt; size, adjust the &lt;code&gt;Typography&lt;/code&gt; variant. But a normal visual editor can only see the &lt;code&gt;items.map(...)&lt;/code&gt; expression. It can't render the inside, because &lt;code&gt;item&lt;/code&gt; is undefined until the loop runs. Same story for a ternary (&lt;code&gt;cond ? &amp;lt;A/&amp;gt; : &amp;lt;B/&amp;gt;&lt;/code&gt;) and for &lt;code&gt;children&lt;/code&gt; passed into a slot.&lt;/p&gt;

&lt;p&gt;That runtime boundary is where most tools stop. Studio treats it as just another layer to step into.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 — Drill into the iteration
&lt;/h2&gt;

&lt;p&gt;There are three ways to drill into a node, and they work whether the target is in the current file or in another one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ctrl+click on the canvas or in the component tree.&lt;/strong&gt; Hover a drillable sub-component or expression and an action prompt appears; hold &lt;code&gt;Ctrl&lt;/code&gt; to highlight the target with a mask, then click to step into it. Or just click the corresponding node in the left component tree.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSX block selector / breadcrumb.&lt;/strong&gt; Use the block selector or breadcrumb above the editor to see the hierarchy and jump to any level — handy when the tree is dense and you'd rather pick than click through.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cursor focus (in-file).&lt;/strong&gt; In the code editor, place your cursor inside a JSX block and Studio promotes it to the canvas focus. Editor and canvas point at the same AST, so moving in one moves the other.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Drill into the &lt;code&gt;.map()&lt;/code&gt; and Studio renders an &lt;strong&gt;isolated canvas for the inner block&lt;/strong&gt; — one iteration of your list, standing on its own.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Flayer-drilldown-infile.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Flayer-drilldown-infile.png" alt="Ctrl+click the .map() to drill into a single list item" width="800" height="554"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Flayer-drilldown-infile2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Flayer-drilldown-infile2.png" alt="Ctrl+click the .map() to drill into a single list item" width="800" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the shot above, Ctrl+click on the &lt;code&gt;.map()&lt;/code&gt; drills into &lt;code&gt;ProjectBoard['map-0-item']&lt;/code&gt; — the first item of the list, isolated on the canvas while the full &lt;code&gt;items.map(...)&lt;/code&gt; stays put in the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Supply the missing context: the Test Data Injector
&lt;/h3&gt;

&lt;p&gt;An isolated list item has a problem: it lost the context its parent gave it. &lt;code&gt;item&lt;/code&gt; is undefined now — there's no loop feeding it. So Studio gives you a &lt;strong&gt;Test Data Injector&lt;/strong&gt;: a panel where you supply temporary mock data (JSON, strings, booleans) for any undefined props or variables at the current level. Fill in &lt;code&gt;item&lt;/code&gt; and the isolated &lt;code&gt;Card&lt;/code&gt; renders realistically, without the full app around it.&lt;/p&gt;

&lt;p&gt;One thing that saves guesswork: &lt;strong&gt;hover any unassigned variable and the code editor highlights its exact location in the source&lt;/strong&gt;, so you can see how &lt;code&gt;item&lt;/code&gt; is used before you decide what to mock.&lt;/p&gt;

&lt;p&gt;Now the &lt;code&gt;Card&lt;/code&gt; is live. Not a screenshot — the actual component, rendered with real MUI theming.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — Edit the inner node
&lt;/h2&gt;

&lt;p&gt;With the inner block isolated, editing is the normal Studio loop. Click the &lt;code&gt;Chip&lt;/code&gt;, change &lt;code&gt;size&lt;/code&gt; from &lt;code&gt;small&lt;/code&gt; to &lt;code&gt;medium&lt;/code&gt;. Select the &lt;code&gt;Card&lt;/code&gt;, promote its padding to a responsive &lt;code&gt;{ xs: 2, md: 3 }&lt;/code&gt;. Each change writes back into the callback body as a precise AST patch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;   {items.map((item) =&amp;gt; (
&lt;span class="gd"&gt;-    &amp;lt;Card key={item.id} elevation={item.featured ? 3 : 1}&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+    &amp;lt;Card key={item.id} elevation={item.featured ? 3 : 1} sx={{ p: { xs: 2, md: 3 } }}&amp;gt;
&lt;/span&gt;       &amp;lt;CardContent&amp;gt;
         &amp;lt;Typography variant="h6"&amp;gt;{item.title}&amp;lt;/Typography&amp;gt;
&lt;span class="gd"&gt;-        &amp;lt;Chip label={item.tag} size="small" /&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+        &amp;lt;Chip label={item.tag} size="medium" /&amp;gt;
&lt;/span&gt;       &amp;lt;/CardContent&amp;gt;
     &amp;lt;/Card&amp;gt;
   ))}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;.map()&lt;/code&gt; wrapper, the &lt;code&gt;key&lt;/code&gt;, the ternary on &lt;code&gt;elevation&lt;/code&gt; — all untouched. Your mock data never touches the file; it lived only in the drill-down session. What lands in the diff is exactly the two properties you changed.&lt;/p&gt;

&lt;p&gt;The same mechanism works for conditional rendering (drill into the &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt; side of a ternary, or a &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; branch, and edit it in isolation), for controlled sub-components that depend on external props or state, and for render-slot &lt;code&gt;children&lt;/code&gt;. Any depth your tree actually has, you can reach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 — Cross the file boundary
&lt;/h2&gt;

&lt;p&gt;Real components don't live in one file — a page composes children that are &lt;code&gt;import&lt;/code&gt;ed from all over &lt;code&gt;src/&lt;/code&gt;. A file-bound editor stops when it hits one of those imported children: you have to go find the file yourself, open it, and lose the canvas.&lt;/p&gt;

&lt;p&gt;Studio doesn't stop there. &lt;strong&gt;Ctrl+click a child component and Studio drills straight into the file where it's defined&lt;/strong&gt;, and keeps rendering it live on the canvas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Flayer-drilldown-crossfile.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Flayer-drilldown-crossfile.png" alt="[Ctrl+click a child component to drill into the file where it's defined" width="800" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Flayer-drilldown-crossfile2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Flayer-drilldown-crossfile2.png" alt="[Ctrl+click a child component to drill into the file where it's defined" width="800" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the shot above, the active file is &lt;code&gt;ShadcnDashboard.jsx&lt;/code&gt;. Its component tree lists the children it composes — &lt;code&gt;KpiCard&lt;/code&gt;, &lt;code&gt;RevenueChart&lt;/code&gt;, &lt;code&gt;OrdersTable&lt;/code&gt;, &lt;code&gt;Sidebar&lt;/code&gt;, &lt;code&gt;Header&lt;/code&gt;, and so on. &lt;code&gt;Sidebar&lt;/code&gt; isn't defined in this file; it's &lt;code&gt;import&lt;/code&gt;ed from &lt;code&gt;./components/Sidebar.jsx&lt;/code&gt; (line 16). Ctrl+click it, and Studio follows the import, opens the real definition, and drops you onto its canvas — the dashboard's sidebar, rendered live — with no manual file hunting and no losing your place. From there you can keep drilling: into that file's own children, into a &lt;code&gt;.map()&lt;/code&gt; inside it, into a component &lt;em&gt;it&lt;/em&gt; imports from somewhere else.&lt;/p&gt;

&lt;p&gt;The same three drill-down methods from Step 1 apply here — Ctrl+click and the JSX block selector both cross file boundaries (cursor focus is the one that's in-file only, since it needs the code open in front of you). The effect is that the component tree stops being one-file-at-a-time. You navigate your UI the way it's actually structured — as a graph of components across files — while the canvas stays live at every hop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it can do this
&lt;/h2&gt;

&lt;p&gt;Same reason the rest of Studio works the way it does: everything is a view over the AST, not over a running app.&lt;/p&gt;

&lt;p&gt;Drilling into a &lt;code&gt;.map()&lt;/code&gt; is an AST operation — Studio finds the callback body node and renders it with an injected scope. Following a child component across files is &lt;em&gt;also&lt;/em&gt; an AST operation — it resolves the &lt;code&gt;import&lt;/code&gt;, parses the target file, locates the exported component, and renders that node. The runtime never has to succeed for any of this; Studio is reading structure, not observing execution. That's why it can isolate a node five levels deep, in a file you haven't opened, whether or not the full app renders.&lt;/p&gt;

&lt;p&gt;If you want the architecture behind that, the &lt;a href="https://blog.crossui.com/2026/06/bypass-the-broken-import" rel="noopener noreferrer"&gt;dependency graph post&lt;/a&gt; covers how static AST parsing survives things a runtime tool can't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;The fastest way to feel this is on a real project with real nesting — a dashboard with a list of cards, a page that composes imported sections.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a project (Playground, Git repo, or a local folder).&lt;/li&gt;
&lt;li&gt;Find a &lt;code&gt;.map()&lt;/code&gt; or a ternary, drill in, use the Test Data Injector to mock the missing variable, and edit the inner node.&lt;/li&gt;
&lt;li&gt;Find an imported child component in the tree, &lt;strong&gt;Ctrl+click&lt;/strong&gt; it, and watch Studio follow it into its own file.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Guest mode, no account: &lt;a href="https://studio.crossui.com" rel="noopener noreferrer"&gt;studio.crossui.com&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About CrossUI Studio&lt;/strong&gt; — A visual IDE for React &amp;amp; MUI. Code and canvas stay in two-way sync on the same AST: edit code and the canvas updates live; click an element on the canvas, edit its props visually, and the code changes with a surgical one-line diff. No build, no localhost — it runs in the browser, works on your real Git repo or a local folder, with no vendor lock-in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://studio.crossui.com" rel="noopener noreferrer"&gt;Try it free → studio.crossui.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>mui</category>
      <category>development</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Developer sovereignty: what "no lock-in" actually means</title>
      <dc:creator>Jack Lee</dc:creator>
      <pubDate>Mon, 29 Jun 2026 12:02:14 +0000</pubDate>
      <link>https://dev.to/linb/developer-sovereignty-what-no-lock-in-actually-means-4j31</link>
      <guid>https://dev.to/linb/developer-sovereignty-what-no-lock-in-actually-means-4j31</guid>
      <description>&lt;p&gt;Every developer tool says "no lock-in" on its landing page. It's the cheapest promise in software — easy to write, almost never tested, and by the time you find out it wasn't true, you've already built six months of work on top of it.&lt;/p&gt;

&lt;p&gt;So instead of saying it, here's the test we hold ourselves to. One question, and it's the only one that matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  The exit test
&lt;/h2&gt;

&lt;p&gt;Stop using the tool tomorrow. Is your project still standard, shippable code that runs without it?&lt;/p&gt;

&lt;p&gt;That's it. Not "can you export." Not "is there a migration path." Those are consolation prizes you accept &lt;em&gt;after&lt;/em&gt; you've already been locked in. The real question is whether the tool ever inserted itself into your source in the first place.&lt;/p&gt;

&lt;p&gt;Run that test against most visual editors and the answer is no:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Export-and-fork tools&lt;/strong&gt; — the moment you export and hand-edit, the tool and your repo are separate forever. There's no exit &lt;em&gt;back&lt;/em&gt;; the design tool can't read your changes. You don't own one project, you maintain two.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SDK-ownership tools&lt;/strong&gt; — your components live in a proprietary model, rendered by the tool's runtime. "Stop using it" means migrating a schema, rewriting components, untangling a dependency you can't remove. The exit cost is the lock-in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI app generators&lt;/strong&gt; — better here, since they hand you code and walk away. But they also walk away from the &lt;em&gt;next&lt;/em&gt; change. They don't stay in sync with the source, because they were never connected to it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pattern: every one of them either never touched your real code, or touched it in a way you can't undo. Sovereignty is the opposite of both — the tool works on your real source, and leaves nothing behind when it goes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we put in writing
&lt;/h2&gt;

&lt;p&gt;We call this principle developer sovereignty, and we made it a concrete guarantee, not a vibe:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The code processed by CrossUI Studio is standard React code.&lt;/strong&gt; We promise not to embed any proprietary runtimes, closed-source dependency packages, or any logic "traps" that cannot run outside the platform into your source files. If you stop using CrossUI Studio, your project remains a standard React project — no migration effort required.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Three things that are &lt;em&gt;not&lt;/em&gt; in your files after Studio touches them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;No proprietary runtime.&lt;/strong&gt; Nothing your app needs to import from us to render. It runs on plain React, the same as before.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No closed-source dependencies.&lt;/strong&gt; We don't slip a package into your &lt;code&gt;package.json&lt;/code&gt; that only resolves through us.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No platform-locked logic.&lt;/strong&gt; No magic comments, no special syntax, no node that only means something inside our canvas.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What's left in your repo is what a senior engineer on your team would have typed by hand. That's the whole point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why we can actually promise this
&lt;/h2&gt;

&lt;p&gt;Most tools can't make this promise because of &lt;em&gt;how&lt;/em&gt; they're built. If a tool owns a rendering model — its own representation of your component tree — then "saving" means serializing that model back to code. Serialization is lossy. The tool writes what it knows and discards what it doesn't, which is why exported code looks subtly foreign and why re-emitting a file strips your comments.&lt;/p&gt;

&lt;p&gt;Studio is built the other way around. Your source code's AST is the single source of truth, and every surface — the canvas, the inspector, the code editor — is just a &lt;em&gt;view&lt;/em&gt; over that AST. We never hold a parallel model that has to be flushed back to disk. When you change a prop on the canvas, we patch the one AST node that changed and write back only the bytes that moved.&lt;/p&gt;

&lt;p&gt;The consequence you can see in &lt;code&gt;git diff&lt;/code&gt;: a padding change is one line. Indistinguishable from what you'd have typed. And because we never owned anything but a view, there's nothing to take with us when you leave — the source was always yours, the whole time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhapr79tn1qwmlbcxoijl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhapr79tn1qwmlbcxoijl.png" alt="Developer sovereignty — your code stays standard React" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sovereignty is a feature, not a disclaimer
&lt;/h2&gt;

&lt;p&gt;It's tempting to read "no lock-in" as a defensive footnote — a thing you promise so buyers feel safe. But for the teams we care about, it's the product.&lt;/p&gt;

&lt;p&gt;A senior engineer evaluating a visual tool isn't asking "is this fun to use." They're asking "what does this do to my codebase, my git history, my code review, six months from now." A tool that leaves the source clean and exits without a trace is one they can actually adopt, because adopting it costs nothing to reverse. The reversibility &lt;em&gt;is&lt;/em&gt; the trust.&lt;/p&gt;

&lt;p&gt;And it compounds outward. Template authors won't ship a tool to their buyers that traps those buyers. Agencies won't hand a client a codebase they can't maintain without a subscription. Sovereignty isn't just your guarantee — it's theirs to pass on.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest version
&lt;/h2&gt;

&lt;p&gt;No lock-in doesn't mean no commitment. While you use Studio, you do connect it to your repo or a local folder — that's the price of real two-way sync, and we think it's worth it. What it means is that the commitment is &lt;em&gt;revocable at any moment, for free&lt;/em&gt;. Close the folder, cancel the plan, delete your account: your project doesn't notice. It was standard React before Studio, during Studio, and after.&lt;/p&gt;

&lt;p&gt;That's the test. Run it on every tool you adopt — including ours.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About CrossUI Studio&lt;/strong&gt; — A visual IDE for React &amp;amp; MUI. Code and canvas stay in two-way sync on the same AST: edit code and the canvas updates live; click an element on the canvas, edit its props visually, and the code changes with a surgical one-line diff. No build, no localhost — it runs in the browser, works on your real Git repo or a local folder, with no vendor lock-in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://studio.crossui.com" rel="noopener noreferrer"&gt;Try it free → studio.crossui.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>nolock</category>
      <category>crossui</category>
    </item>
    <item>
      <title>Your AI writes the logic. Studio tunes the UI. They don't compete.</title>
      <dc:creator>Jack Lee</dc:creator>
      <pubDate>Mon, 22 Jun 2026 16:43:44 +0000</pubDate>
      <link>https://dev.to/linb/your-ai-writes-the-logic-studio-tunes-the-ui-they-dont-compete-4jf5</link>
      <guid>https://dev.to/linb/your-ai-writes-the-logic-studio-tunes-the-ui-they-dont-compete-4jf5</guid>
      <description>&lt;p&gt;I was building a dashboard. The card layout was almost right — just needed a bit more breathing room, a tighter border radius on the inner rows, and the label font to feel slightly lighter. Three small things.&lt;/p&gt;

&lt;p&gt;I typed the description into Cursor. It came back with 180 lines rewritten. Every &lt;code&gt;sx&lt;/code&gt; prop touched, four components restructured, a new wrapper &lt;code&gt;div&lt;/code&gt; appeared. The layout looked the same. The diff was enormous.&lt;/p&gt;

&lt;p&gt;I hit &lt;code&gt;Ctrl+Z&lt;/code&gt; and went back to staring at the code.&lt;/p&gt;

&lt;p&gt;That was the moment I stopped thinking of AI as a universal tool and started thinking of it as a &lt;em&gt;specific&lt;/em&gt; tool — an exceptionally good one, for specific things.&lt;/p&gt;

&lt;h2&gt;
  
  
  What AI is actually good at
&lt;/h2&gt;

&lt;p&gt;AI editors are brilliant at the parts of React development that are fundamentally about &lt;em&gt;thinking&lt;/em&gt;: data flow, state architecture, API wiring, conditional rendering logic, form validation, accessibility semantics, refactoring towards patterns. These are tasks where the right answer involves reasoning across the whole codebase, holding context, understanding intent.&lt;/p&gt;

&lt;p&gt;When I ask an AI to "add optimistic update to this mutation handler" or "extract this form logic into a custom hook" — I get back something genuinely useful, usually on the first try.&lt;/p&gt;

&lt;h2&gt;
  
  
  What AI is genuinely bad at
&lt;/h2&gt;

&lt;p&gt;UI polish is a different category. Not because AI can't read CSS — it clearly can. But because getting a layout &lt;em&gt;exactly right&lt;/em&gt; is an iterative, visual, trial-and-error process. You need to &lt;em&gt;see&lt;/em&gt; the result immediately. You need to tweak a value, check it, tweak again.&lt;/p&gt;

&lt;p&gt;The AI-for-UI workflow is fundamentally broken:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Describe what you want in words (already lossy)&lt;/li&gt;
&lt;li&gt;Wait for the model to generate a response&lt;/li&gt;
&lt;li&gt;Review 200 lines of diff&lt;/li&gt;
&lt;li&gt;Wait for the build&lt;/li&gt;
&lt;li&gt;See the result — probably not right&lt;/li&gt;
&lt;li&gt;Repeat, burning tokens each round&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The bigger the model's context about your component, the more it rewrites. It doesn't know how to make a surgical one-property change, because its job is to understand and regenerate, not to minimally diff.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AI is expensive at precision. It's cheap at breadth. UI tuning needs precision. Logic needs breadth. Match the tool to the task.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Where each tool belongs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;AI Editor (Cursor / Claude / Copilot)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Component architecture and refactoring&lt;/li&gt;
&lt;li&gt;State management and data flow&lt;/li&gt;
&lt;li&gt;API integration and async logic&lt;/li&gt;
&lt;li&gt;Accessibility and semantics&lt;/li&gt;
&lt;li&gt;Test generation&lt;/li&gt;
&lt;li&gt;Large-scale rewrites and migrations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;CrossUI Studio&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spacing, sizing, layout tweaks&lt;/li&gt;
&lt;li&gt;MUI &lt;code&gt;sx&lt;/code&gt; and responsive breakpoints&lt;/li&gt;
&lt;li&gt;Color, typography, visual hierarchy&lt;/li&gt;
&lt;li&gt;Deep-layer UI drill-down and isolation&lt;/li&gt;
&lt;li&gt;Rapid iterative visual feedback&lt;/li&gt;
&lt;li&gt;Surgical one-property diffs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice there's no overlap. That's not accidental — these tools solve genuinely different problems. The goal was never to have one tool do everything. It was to cover the full surface of React development without gaps.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pairing in practice
&lt;/h2&gt;

&lt;p&gt;Since we shipped Local Folder access in v0.9.6, the workflow is concrete: point both your AI editor &lt;em&gt;and&lt;/em&gt; Studio at the same folder on your machine. They work on the same files simultaneously. One writes logic, the other tunes UI. The diff in Git is always clean because every change is surgical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — AI builds the component&lt;/strong&gt;&lt;br&gt;
Cursor or Claude writes the data-fetching hook, the conditional render, the event handlers. Full context, full reasoning, exactly what it's good at.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — Studio opens the same folder&lt;/strong&gt;&lt;br&gt;
No upload, no sync, no token. Studio reads the files directly off disk — the canvas shows your component live.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — You tune visually&lt;/strong&gt;&lt;br&gt;
Adjust spacing, colors, and layout directly on the canvas. The code updates in real-time. One property changed = one property in the diff.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4 — PR lands clean&lt;/strong&gt;&lt;br&gt;
Logic changes from AI. UI changes from Studio. Both are minimal, reviewable, and traceable. No 200-line rewrites for a border-radius tweak.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means for "AI replacing developers"
&lt;/h2&gt;

&lt;p&gt;There's a lot of anxiety right now about AI eating programming jobs. Some of it is warranted — the volume of boilerplate code a developer needs to write by hand has dropped dramatically, and it's not coming back.&lt;/p&gt;

&lt;p&gt;But the anxiety assumes AI is a single homogeneous capability that scales linearly. It isn't. There are things AI does cheaply and well (reasoning, pattern-matching, generation at scale) and things it does poorly or expensively (precise iterative feedback loops, visual judgment, knowing when to stop).&lt;/p&gt;

&lt;p&gt;The developer who understands this boundary — and builds a workflow around it — is faster than the developer who either ignores AI entirely &lt;em&gt;or&lt;/em&gt; tries to use it for everything. The job doesn't disappear. It shifts: less time writing boilerplate, more time designing systems and judging quality.&lt;/p&gt;

&lt;p&gt;Studio is a bet on that shift. Not a replacement for AI. Not a rejection of it. A tool for the part of your work that AI handles badly — so you can let AI fully own the part it handles well.&lt;/p&gt;




&lt;p&gt;If you've been using an AI editor and hitting the same wall on UI iteration — try the pairing. Open Studio, point it at your project folder, and see if the division of labor clicks for you.&lt;/p&gt;

&lt;p&gt;No account needed — &lt;a href="https://studio.crossui.com/app" rel="noopener noreferrer"&gt;Guest mode&lt;/a&gt; opens a workspace instantly. Or connect a local folder and work on your real files.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About CrossUI Studio&lt;/strong&gt; — A visual IDE for React &amp;amp; MUI. Code and canvas stay in two-way sync on the same AST: edit code and the canvas updates live; click an element on the canvas, edit its props visually, and the code changes with a surgical one-line diff. No build, no localhost — it runs in the browser, works on your real Git repo or a local folder, with no vendor lock-in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://studio.crossui.com" rel="noopener noreferrer"&gt;Try it free → studio.crossui.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>ai</category>
      <category>cursor</category>
      <category>dx</category>
    </item>
    <item>
      <title>Don't just find the broken import. Bypass it.</title>
      <dc:creator>Jack Lee</dc:creator>
      <pubDate>Mon, 22 Jun 2026 16:07:49 +0000</pubDate>
      <link>https://dev.to/linb/dont-just-find-the-broken-import-bypass-it-56hf</link>
      <guid>https://dev.to/linb/dont-just-find-the-broken-import-bypass-it-56hf</guid>
      <description>&lt;p&gt;A dependency five levels down throws, and your whole canvas goes white. CrossUI Studio's Dependency Graph still draws — zero build — points you straight at the blinking node, and then lets you inject a mock for the broken module to bring the page back. No file edit. No rebuild.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Dependency Graph is built from static AST parsing, not a build — open a file and the import tree renders instantly, even when the canvas has completely crashed. The failing module blinks with its exact line/column. Then the part that's actually new: from the inspector you can set an interceptor or override to swap the broken dependency for a mock, hit Apply Dependency Injection, and the render comes back — rules auto-persist per entry file.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The blank-screen problem, five levels deep
&lt;/h2&gt;

&lt;p&gt;A component blows up, but the component is never the culprit. Here's a real one. The canvas throws inside &lt;code&gt;AIPanel.jsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error (Canvas render — runtime)
Parser engine initialization aborted.
  in Studio/src/components/panels/AIPanel.jsx

  at initializeParser (Engine/src/TreeSitter.js:32:11)
  at async Engine/src/TreeSitter.js:36:31
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But &lt;code&gt;AIPanel&lt;/code&gt; isn't where it broke. The real failure is in &lt;code&gt;TreeSitter.js&lt;/code&gt;, line 32 — &lt;strong&gt;five imports down&lt;/strong&gt; the chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AIPanel.jsx → AIJsxResponseReconciler.js → JSXParserEngine.js
            → CodeFormatter.js → TreeSitter.js   ← throws here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Normally this is where the afternoon disappears: rebuild to reproduce, scatter &lt;code&gt;console.log&lt;/code&gt;s down the chain, guess which import actually threw. And the tools built to help have all just gone dark — React DevTools shows nothing (no component mounted), the profiler has no render to profile, the error overlay gives you a line but not the &lt;em&gt;shape&lt;/em&gt; of the code around it. They all need the app to run first. It didn't.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The one moment you most need to understand your code's structure is the one moment your code refuses to produce it.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Zero build, instant display
&lt;/h2&gt;

&lt;p&gt;The Dependency Graph skips the build step entirely. Open a file and it parses the &lt;code&gt;import&lt;/code&gt; tree to an AST and draws it in real time — no bundling, no dev-server round-trip, no waiting. That alone is the everyday time-saver: you see the whole reachable module graph the instant you ask for it, not after a rebuild.&lt;/p&gt;

&lt;p&gt;And because the map is parsed from &lt;em&gt;source&lt;/em&gt; rather than observed from a &lt;em&gt;run&lt;/em&gt;, it has a property no runtime tool can match: it still renders when the canvas has completely crashed. A broken page isn't a dead end — it's the graph's primary entry point.&lt;/p&gt;




&lt;h2&gt;
  
  
  Two ways to know a codebase
&lt;/h2&gt;

&lt;p&gt;There are only two ways for a tool to learn the shape of your project, and the difference decides everything about when the tool is available to you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runtime introspection&lt;/strong&gt; — needs a successful render. React DevTools, profilers, error overlays. Reads the live fiber tree after mount, knows real prop values — but only if they exist. Goes completely dark when the render throws, and can't see a module that failed to initialize.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Static AST analysis&lt;/strong&gt; — needs nothing to run. CrossUI's Dependency Graph parses each file to an AST and reads its imports. Knows structure — every edge, before execution — indifferent to whether the app renders, and maps the broken module &lt;em&gt;and&lt;/em&gt; its neighbors.&lt;/p&gt;

&lt;p&gt;Runtime tools are richer when they work. But they are &lt;strong&gt;conditional on success&lt;/strong&gt;. Static analysis is poorer in some ways — it can't tell you what a variable held at 2:04pm — but it is &lt;strong&gt;unconditional&lt;/strong&gt;. It works on a codebase that has never once rendered cleanly. That property is the whole point.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reading the graph
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8trzo849e37o6yu348n4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8trzo849e37o6yu348n4.png" alt="Dependency Graph" width="800" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Set any file as the &lt;code&gt;ENTRY&lt;/code&gt; and the panel scans outward from it. Every node is tagged so you can place it at a glance: &lt;code&gt;Entry&lt;/code&gt;, &lt;code&gt;📄 Local&lt;/code&gt;, &lt;code&gt;🌐 Ext&lt;/code&gt;, and &lt;code&gt;⟳ Cyclic&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hover or select a node and animated lines trace its relationships in two directions — and the direction is the whole point:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Solid lines — downstream.&lt;/strong&gt; The modules this file imports.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dashed lines — upstream.&lt;/strong&gt; The parents that import &lt;em&gt;this&lt;/em&gt; file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The search box highlights matching nodes live; the failing module &lt;strong&gt;blinks&lt;/strong&gt; so your eye lands on it without hunting.&lt;/p&gt;

&lt;p&gt;Click any node and the inspector slides out — your troubleshooting console for that file. It shows the resolved path, the raw &lt;code&gt;source&lt;/code&gt; string and its &lt;code&gt;resolvedSource&lt;/code&gt;, and, when parsing hit trouble, the exact error in red with line and column:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inspector · TreeSitter.js                     📄 Local
  specifiers       { parserInstance }
  source           ./TreeSitter.js
  resolvedSource   Engine/src/TreeSitter.js
  error            Parser engine initialization aborted · Line 32, Column 12
  interceptor      [ intercept source… ]
  override         [ override resolved path… ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigation note: mouse-wheel pans vertically, &lt;code&gt;Shift&lt;/code&gt;+wheel pans horizontally, &lt;code&gt;Ctrl&lt;/code&gt;+wheel zooms on the cursor — so a huge graph stays fast to move through.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cycles, in red and one click away
&lt;/h3&gt;

&lt;p&gt;The engine detects circular references and draws the offending edge in red. A &lt;strong&gt;Show cycles&lt;/strong&gt; filter in the bottom-left isolates just the nodes caught in a loop. Inside the inspector, a node in a cycle shows the full closed-loop chain — and hovering the chain highlights every related node on the canvas, while clicking a name in the chain selects and focuses that file. Circular imports are the quiet cause of a whole genre of bugs — a module that's &lt;code&gt;undefined&lt;/code&gt; at first access, lazy chunks that won't split, "works on the second hot-reload" gremlins. The graph just shows you the loop instead of making you find it by accident.&lt;/p&gt;




&lt;h2&gt;
  
  
  The part that's actually new: bypass the broken module
&lt;/h2&gt;

&lt;p&gt;Finding the blinking node is good. But the Dependency Graph goes one step further than any read-only map: it lets you &lt;strong&gt;swap the broken dependency for a mock and bring the render back&lt;/strong&gt; — without editing the file and without a rebuild. Two injection levers, both in the inspector:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interceptor&lt;/strong&gt; — match on the &lt;code&gt;import … from 'yyy'&lt;/code&gt; declaration. The &lt;code&gt;source&lt;/code&gt; string shown on the node is exactly the word you intercept.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Override&lt;/strong&gt; — match on the final physical path the system resolved to. The &lt;code&gt;resolvedSource&lt;/code&gt; on the node is exactly the path you override.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Configure either, then click the highlighted &lt;strong&gt;Apply Dependency Injection&lt;/strong&gt; button in the top toolbar. Studio injects your rule into the current rendering context and attempts to restore the visualization — the deep, crashing module is now standing in for itself with something that renders. And the rules &lt;strong&gt;auto-persist, keyed by the entry file&lt;/strong&gt;: reopen the same page tomorrow and your injection is already in place.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A read-only graph tells you where it broke. This one lets you route around the break and keep working — the file untouched, the page alive.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The render-error resolution flow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Locate the blinking node.&lt;/strong&gt; Open the graph from the error overlay's &lt;strong&gt;Show Dependency Graph&lt;/strong&gt; link. The module that crashed the render is already blinking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Investigate the root cause.&lt;/strong&gt; Follow the line/column on the node, double-click to open that exact file, and find the offending code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolate with injection.&lt;/strong&gt; If a deep dependency is the cause, set an &lt;code&gt;interceptor&lt;/code&gt; (on &lt;code&gt;source&lt;/code&gt;) or &lt;code&gt;override&lt;/code&gt; (on &lt;code&gt;resolvedSource&lt;/code&gt;) in the inspector to swap it for a mock.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply to restore the render.&lt;/strong&gt; Click &lt;strong&gt;Apply Dependency Injection&lt;/strong&gt;. The rule is injected into the rendering context and the page attempts to come back — no rebuild.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence handles the rest.&lt;/strong&gt; Your rules are saved locally against this entry file and restored automatically next time. Re-enter nothing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/HZ7T4MFcqg8"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is the same thesis as everything else
&lt;/h2&gt;

&lt;p&gt;If you read &lt;a href="https://blog.crossui.com/2026/05/why-we-rejected-the-export-and-fork-model-for-visual-ui-editing" rel="noopener noreferrer"&gt;our first post&lt;/a&gt;, this will feel familiar. The reason a CrossUI visual edit produces a one-line git diff is the same reason the Dependency Graph survives a crash and can inject around it: &lt;strong&gt;we treat your parsed source as the source of truth, and every surface is just a view over that AST.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The canvas is a view over the AST. The prop inspector is a view over the AST. The Dependency Graph is a view over the AST &lt;em&gt;across files&lt;/em&gt; — and injection is a controlled rewrite of how one edge resolves. None of it depends on your app successfully running, because none of it is built on the runtime. That's a constraint we chose on purpose — it's harder to build, and it's exactly what keeps the tooling alive in the moments runtime tools abandon you.&lt;/p&gt;




&lt;h2&gt;
  
  
  What it can't do — honestly
&lt;/h2&gt;

&lt;p&gt;Static analysis buys unconditional availability by giving up runtime knowledge. The boundaries are real and we'd rather name them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fully dynamic imports are unresolvable.&lt;/strong&gt; A dynamic &lt;code&gt;import('./pages/' + name)&lt;/code&gt; with a runtime-computed path can't be resolved statically — we mark the edge rather than guess wrong.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;It shows structure, not values.&lt;/strong&gt; The graph tells you &lt;code&gt;AIPanel&lt;/code&gt; reaches &lt;code&gt;TreeSitter&lt;/code&gt;; it can't tell you what the parser returned this particular render. Injection mocks the dependency; it doesn't replay the runtime state.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Exotic resolution needs config.&lt;/strong&gt; Non-standard bundler aliases or monorepo path magic resolve best when we can read your &lt;code&gt;tsconfig&lt;/code&gt; / jsconfig. Without it, some edges fall back to raw specifiers.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of those change the core promise: the graph is there when you're stuck, and it can route you around the break — because it never needed your code to run.&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://studio.crossui.com" rel="noopener noreferrer"&gt;Open Studio&lt;/a&gt; — crash a deep dependency, watch the graph point at it, then inject a mock and click Apply.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About CrossUI Studio&lt;/strong&gt; — A visual IDE for React &amp;amp; MUI. Code and canvas stay in two-way sync on the same AST: edit code and the canvas updates live; click an element on the canvas, edit its props visually, and the code changes with a surgical one-line diff. No build, no localhost — it runs in the browser, works on your real Git repo or a local folder, with no vendor lock-in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://studio.crossui.com" rel="noopener noreferrer"&gt;Try it free → studio.crossui.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>development</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Add "Try in Studio" to Your React Tutorials in 5 Minutes</title>
      <dc:creator>Jack Lee</dc:creator>
      <pubDate>Mon, 22 Jun 2026 14:40:38 +0000</pubDate>
      <link>https://dev.to/linb/add-try-in-studio-to-your-react-tutorials-in-5-minutes-5f68</link>
      <guid>https://dev.to/linb/add-try-in-studio-to-your-react-tutorials-in-5-minutes-5f68</guid>
      <description>&lt;p&gt;&lt;em&gt;~7 min read  ·TUTORIAL&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Your readers copy-paste your code examples. Wouldn't it be better if they could try them live, in the browser, right from your article? Add an "Open in Studio" button with a single script tag. No build, no local setup, no dependencies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fguest-snapshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.crossui.com%2Fimages%2Fguest-snapshot.png" alt="CrossUI Studio — visual IDE for React and MUI" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bridge is how Studio reaches your audience. If you write React tutorials, teach courses, sell component templates, or build UIs for clients — one button turns your static code examples into live, editable Studio workspaces. This is how you set it up.&lt;/p&gt;

&lt;h2&gt;
  
  
  FOR PARTNERS
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This is how partners bring Studio to their audience.&lt;/strong&gt; Add one line of code and your tutorials, courses, or templates get a visual IDE built in. Your readers learn better. Your students skip setup. Your templates sell themselves. Your clients sign off faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Bridge?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;You already have great content, courses, or templates.&lt;/strong&gt; Bridge makes them more valuable with zero effort on your side:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;For Tutorial &amp;amp; Content Partners:&lt;/strong&gt; Transform static snippets into live, tweakable playgrounds. Readers experiment instead of just reading. No hosting, no infra — it's free and maintenance-free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For Template Authors:&lt;/strong&gt; Offer buyers a "Try Before You Buy" visual preview. They visually edit layouts without touching React code, drastically reducing support tickets. Templates sell themselves.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For Instructors &amp;amp; Bootcamps:&lt;/strong&gt; Your students get free Pro for 1 month per cohort. They skip npm install, environment hell, localhost issues. Jump straight into visual React learning. Your course feels more premium.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For Agencies:&lt;/strong&gt; Co-design UIs with clients in real-time. Visual edits immediately generate clean, PR-ready React code. Sign-offs faster, less back-and-forth.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;One button. Your audience gets a better experience. You get more value from the work you've already done.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Three integration paths
&lt;/h2&gt;

&lt;p&gt;Pick one based on your site's tech stack:&lt;/p&gt;

&lt;h3&gt;
  
  
  Path 1: HTML Form (Simplest)
&lt;/h3&gt;

&lt;p&gt;Works on static blogs, markdown CMS, or anywhere you can paste raw HTML. Just a form with a button.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Copy this HTML&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"https://studio.crossui.com/public/bridge.php"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt; &lt;span class="na"&gt;target=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;textarea&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"code"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display:none;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
import React from 'react';
import { Button } from '@mui/material';

export default function Demo() {
  return &lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt; &lt;span class="na"&gt;variant=&lt;/span&gt;&lt;span class="s"&gt;"contained"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hello!&lt;span class="nt"&gt;&amp;lt;/Button&amp;gt;&lt;/span&gt;;
}
  &lt;span class="nt"&gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"ref"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"YOUR_REF_CODE"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Open in CrossUI Studio&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Customize the button (optional)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Style it to match your site. It's just a standard form button — use your own CSS. Add an &lt;code&gt;origin&lt;/code&gt; parameter if you want to track which page sends traffic (helpful for knowing what's working).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"origin"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"my-react-tutorial-page"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Paste the React code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Replace the &lt;code&gt;import React...&lt;/code&gt; block with your actual component. That's it. You're done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Styling?&lt;/strong&gt; Add CSS to the button element. It's just a standard form button. You can style it however you want.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://studio.crossui.com/public/bridge-demo-html.html" rel="noopener noreferrer"&gt;Live demo — HTML Form&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Path 2: JS SDK (Most Automatic)
&lt;/h3&gt;

&lt;p&gt;For documentation sites or blogs where you have many code blocks. The SDK automatically finds them, injects buttons, and handles the rest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Add the script&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://studio.crossui.com/public/CrossUI-Bridge-Client.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Place it near the end of your &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Initialize with your config&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="nx"&gt;CrossUIBridge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pre code.language-jsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// Target JSX blocks&lt;/span&gt;
  &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_REF_CODE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;              &lt;span class="c1"&gt;// Your partner code&lt;/span&gt;
  &lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-blog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;                  &lt;span class="c1"&gt;// Optional: analytics&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script scans your page for code blocks matching that CSS selector and adds a button to each one.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://studio.crossui.com/public/bridge-demo-js-sdk.html" rel="noopener noreferrer"&gt;Live demo — JS SDK&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Markdown blog?&lt;/strong&gt; Most markdown renders code as &lt;code&gt;&amp;lt;pre&amp;gt;&amp;lt;code class="language-jsx"&amp;gt;...&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&lt;/code&gt;. Set &lt;code&gt;selector: 'pre code.language-jsx'&lt;/code&gt; (or your markdown's class). The SDK does the rest.&lt;/p&gt;

&lt;h3&gt;
  
  
  Path 3: Server-Side (Most Flexible)
&lt;/h3&gt;

&lt;p&gt;For premium template marketplaces or enterprise sites where you want to validate the user's purchase before showing them the code. Your backend receives the request, checks the user's access, and if OK, injects your partner code before redirecting to Studio.&lt;/p&gt;

&lt;p&gt;See the &lt;a href="https://github.com/linb/CrossUI-Studio-Bridge" rel="noopener noreferrer"&gt;GitHub bridge folder&lt;/a&gt; for full examples in Node, PHP, C#, and Java.&lt;/p&gt;

&lt;h2&gt;
  
  
  What do your readers / students / clients get?
&lt;/h2&gt;

&lt;p&gt;One click. Zero setup. They land in Studio with full IDE power:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Instant feedback:&lt;/strong&gt; Edit code, see changes live on the canvas in real-time (SCD — Synchronized Code &amp;amp; Design)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No environment hell:&lt;/strong&gt; No npm install, no localhost, no waiting. Works in any browser, on any device.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visual + Code:&lt;/strong&gt; Drill down any layer in the component tree, edit styles visually, tweak props, understand the structure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guest access:&lt;/strong&gt; No sign-up required. They get the full IDE experience immediately.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; Your readers learn better. Your students skip friction. Your templates show themselves. Your clients buy with confidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ready to bring Studio to your audience?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Three easy steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pick your integration path&lt;/strong&gt; — HTML Form (simplest), JS SDK (most automatic), or Server-Side (most control)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the full guide:&lt;/strong&gt; See the &lt;a href="https://github.com/linb/CrossUI-Studio-Bridge" rel="noopener noreferrer"&gt;GitHub bridge folder&lt;/a&gt; for all three paths with code examples in Node, PHP, C#, and Java.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply to become a partner:&lt;/strong&gt; &lt;a href="https://studio.crossui.com/partners" rel="noopener noreferrer"&gt;Fill out the partnership form&lt;/a&gt; and we'll get back to you in 48 hours with setup docs and everything you need.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Bring Studio to your audience.
&lt;/h2&gt;

&lt;p&gt;Make your content interactive. Make your courses friction-free. Make your templates sell themselves.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://studio.crossui.com/partners" rel="noopener noreferrer"&gt;Become a Partner →&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About CrossUI Studio&lt;/strong&gt; — A visual IDE for React &amp;amp; MUI. Code and canvas stay in two-way sync on the same AST: edit code and the canvas updates live; click an element on the canvas, edit its props visually, and the code changes with a surgical one-line diff. No build, no localhost — it runs in the browser, works on your real Git repo or a local folder, with no vendor lock-in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://studio.crossui.com" rel="noopener noreferrer"&gt;Try it free → studio.crossui.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>tutorial</category>
      <category>bridge</category>
      <category>crossui</category>
    </item>
    <item>
      <title>Why we rejected the export-and-fork model for visual UI editing</title>
      <dc:creator>Jack Lee</dc:creator>
      <pubDate>Mon, 22 Jun 2026 13:16:56 +0000</pubDate>
      <link>https://dev.to/linb/why-we-rejected-the-export-and-fork-model-for-visual-ui-editing-d5g</link>
      <guid>https://dev.to/linb/why-we-rejected-the-export-and-fork-model-for-visual-ui-editing-d5g</guid>
      <description>&lt;p&gt;&lt;em&gt;~10 min read · Engineering&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;There are roughly three honest ways a visual editing tool can relate to your codebase.&lt;/p&gt;

&lt;p&gt;The first is &lt;strong&gt;export and fork&lt;/strong&gt;: you design in the tool, it generates code, you paste it into your project, and from that moment forward the tool and your repo are strangers. This is how most AI code generators (v0, Bolt, Lovable) work — and for greenfield components, it's fine. You generate, you customize, you ship.&lt;/p&gt;

&lt;p&gt;The second is &lt;strong&gt;SDK ownership&lt;/strong&gt;: the tool becomes a runtime dependency. Your components are stored in a proprietary model, rendered via the tool's SDK, and deployed through the tool's infrastructure. Leave the tool, and you're migrating a schema, not just moving files. This is roughly how Plasmic and Builder.io work — and again, for the right use case (marketing pages, designer-editable CMS content), it makes sense.&lt;/p&gt;

&lt;p&gt;The third — the one we bet CrossUI Studio on — doesn't have a clean industry name yet. We call it &lt;strong&gt;Symmetric Collaborative Development (SCD)&lt;/strong&gt;: your React source code is the single source of truth, and the visual canvas is a peer editor of that source. Every visual change is written back to your file as a precise AST patch. No export step. No SDK. No lock-in. Stop using the tool tomorrow and nothing breaks.&lt;/p&gt;

&lt;p&gt;This post explains why we think the third model is the right one for senior engineers maintaining real codebases — and what it actually takes to build it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR.&lt;/strong&gt; If your existing repo is the source of truth and you want a visual layer over it, the editor has to write back through the AST — atomically, one property at a time — or it will lose against your code reviewer. Everything else is a different product for a different team.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The git diff test
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv4u4g82qkag5u3a1kghu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv4u4g82qkag5u3a1kghu.png" alt="Export Fork" width="799" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the simplest way to evaluate any visual editor. Three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the tool with a real MUI component already in your codebase.&lt;/li&gt;
&lt;li&gt;Change &lt;code&gt;variant="text"&lt;/code&gt; to &lt;code&gt;variant="contained"&lt;/code&gt; on a button.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;git diff&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every "design-to-code" tool I evaluated over the last five years failed this test, in one of two ways. Either the file was &lt;strong&gt;re-emitted entirely&lt;/strong&gt; — comments stripped, formatting normalized, imports reshuffled, hand-tuned &lt;code&gt;useMemo&lt;/code&gt; blocks subtly rearranged — or the tool refused to touch existing files at all and emitted a parallel "design document" we then had to glue back into the project.&lt;/p&gt;

&lt;p&gt;Neither was acceptable for a team that takes diff hygiene seriously. We rejected three tools in a row on this basis.&lt;/p&gt;

&lt;p&gt;The third time, I decided the category itself was wrong.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why "re-emit the file" is such a hard habit to break
&lt;/h2&gt;

&lt;p&gt;If you read how most visual editors are architected, the root assumption is: &lt;strong&gt;the tool owns the rendering model&lt;/strong&gt;. The tool maintains its own representation of the component tree — either in a proprietary schema or in an in-memory tree — and "saving" means serializing that representation back to JSX.&lt;/p&gt;

&lt;p&gt;Serialization is lossy by nature. The tool's model doesn't know about your comment. It doesn't know why you named a variable &lt;code&gt;isSaving&lt;/code&gt;. It doesn't know that your &lt;code&gt;/* Main content area */&lt;/code&gt; block comment is something a human will read in code review. So when it writes back, it writes what it knows — the component structure, the props, the styles — and silently discards everything it doesn't.&lt;/p&gt;

&lt;p&gt;The result is a visually identical file that is a &lt;em&gt;conceptually different&lt;/em&gt; file. Same output, different authorship. If you're a senior engineer who cares about your codebase, that's enough reason to never use the tool again.&lt;/p&gt;

&lt;p&gt;The only way to avoid this is to not use serialization at all. Which means working at the AST level from the start — and the AST is hard.&lt;/p&gt;




&lt;h2&gt;
  
  
  What AST-level sync actually requires
&lt;/h2&gt;

&lt;p&gt;Abstract Syntax Trees are how JavaScript parsers represent code internally. Every identifier, every JSX attribute, every function call has a position in the tree. If you want to change &lt;code&gt;variant="outlined"&lt;/code&gt; to &lt;code&gt;variant="contained"&lt;/code&gt;, you don't re-serialize the whole file — you find the &lt;code&gt;JSXAttribute&lt;/code&gt; node whose name is &lt;code&gt;variant&lt;/code&gt;, update its &lt;code&gt;StringLiteral&lt;/code&gt; value, and write back only the characters that changed.&lt;/p&gt;

&lt;p&gt;This is what CrossUI Studio's engine does. The practical consequences:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Formatting is preserved.&lt;/strong&gt; We don't pass the file through Prettier on every visual edit (though we do run Prettier on deliberate code saves). The unchanged bytes don't move.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Comments survive.&lt;/strong&gt; AST nodes have attached comment ranges. We track them and leave them where they are.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Business logic is untouched.&lt;/strong&gt; The engine identifies which AST node corresponds to the visual change and patches only that node. Your custom hooks, your &lt;code&gt;useCallback&lt;/code&gt; wrappers, your conditional rendering logic above and below the component — we don't touch any of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The undo stack is unified.&lt;/strong&gt; Whether you typed in the code editor, dragged a component on the canvas, or changed a value in the inspector, every operation is a reversible AST mutation. &lt;code&gt;Ctrl+Z&lt;/code&gt; rolls back the code and the canvas in sync.&lt;/p&gt;

&lt;p&gt;The visible result for the engineer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;   {/* keep until the new spec lands — Jordan, Apr 14 */}
   const total = useMemo(() =&amp;gt; sum(order.items), [order])
   return (
     &amp;lt;Card sx={{ p: 2 }}&amp;gt;
&lt;span class="gd"&gt;-      &amp;lt;Button variant="text" onClick={handle}&amp;gt;Pay&amp;lt;/Button&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+      &amp;lt;Button variant="contained" onClick={handle}&amp;gt;Pay&amp;lt;/Button&amp;gt;
&lt;/span&gt;     &amp;lt;/Card&amp;gt;
   )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One line removed, one line added. The comment, the &lt;code&gt;useMemo&lt;/code&gt;, the surrounding JSX — byte-identical to before. &lt;strong&gt;The diff that lands in code review is exactly the change the engineer would have typed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/TOiYf7aN4yo"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  The depth problem: why &lt;code&gt;.map&lt;/code&gt; is the real test
&lt;/h2&gt;

&lt;p&gt;Even among tools that do some form of code-aware editing, almost all share the same limitation: they can only operate on the outermost JSX block.&lt;/p&gt;

&lt;p&gt;Consider this common pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;elevation&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;featured&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CardContent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Typography&lt;/span&gt; &lt;span class="na"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"h6"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Typography&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;CardContent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;))}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A typical visual editor sees the &lt;code&gt;map&lt;/code&gt; expression. It cannot edit the &lt;code&gt;Card&lt;/code&gt; inside it visually — because to render a canvas for the &lt;code&gt;Card&lt;/code&gt;, it needs to know what &lt;code&gt;item&lt;/code&gt; is, and &lt;code&gt;item&lt;/code&gt; only exists at runtime inside the callback.&lt;/p&gt;

&lt;p&gt;CrossUI's &lt;strong&gt;Layer Drill-down Engine&lt;/strong&gt; solves this with a Test Data Injector. When you drill into a &lt;code&gt;.map&lt;/code&gt; callback, Studio asks: &lt;em&gt;"what's the shape of &lt;code&gt;item&lt;/code&gt;?"&lt;/em&gt; You provide a mock value — or it infers one from surrounding usage — and Studio renders an isolated canvas for the inner block, with &lt;code&gt;item&lt;/code&gt; injected as a real prop. You edit the &lt;code&gt;Card&lt;/code&gt; visually. The changes are written back to the callback body as precise AST patches. The outer &lt;code&gt;items.map(...)&lt;/code&gt; expression is untouched.&lt;/p&gt;

&lt;p&gt;The same mechanism works for ternary branches (&lt;code&gt;cond ? &amp;lt;A/&amp;gt; : &amp;lt;B/&amp;gt;&lt;/code&gt;) and &lt;code&gt;children&lt;/code&gt; render slots. You can drill &lt;em&gt;any&lt;/em&gt; depth your component tree requires.&lt;/p&gt;

&lt;p&gt;This is the feature that separates a toy from a tool you'd actually use on a production codebase.&lt;/p&gt;




&lt;h2&gt;
  
  
  MUI isn't generic React
&lt;/h2&gt;

&lt;p&gt;One more thing the "re-emit" tools get wrong: they treat all React components the same.&lt;/p&gt;

&lt;p&gt;MUI components have a richer prop surface than native HTML. &lt;code&gt;variant&lt;/code&gt;, &lt;code&gt;size&lt;/code&gt;, &lt;code&gt;color&lt;/code&gt;, &lt;code&gt;elevation&lt;/code&gt;, &lt;code&gt;sx&lt;/code&gt; — these aren't just &lt;code&gt;className&lt;/code&gt; strings. They're typed, enumerated, and in some cases highly structured. The &lt;code&gt;sx&lt;/code&gt; prop accepts a deep object with pseudo-class keys, state-based keys, and responsive breakpoint objects like &lt;code&gt;{ xs: 'small', md: 'large' }&lt;/code&gt;. Generic React visual editors render an untyped text field for &lt;code&gt;sx&lt;/code&gt; and call it done.&lt;/p&gt;

&lt;p&gt;CrossUI Studio ships a dedicated MUI panel with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enumeration completions&lt;/strong&gt; for every MUI prop value (correct values, no guessing).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;sx&lt;/code&gt; tree editor&lt;/strong&gt; — nested objects, pseudo-classes, and media queries in a structured visual tree.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive property promotion&lt;/strong&gt; — click the lightning icon next to any MUI system prop and it splits into a breakpoint object. Change the value at LG and the code becomes &lt;code&gt;size={{ xs: 'small', lg: 'medium' }}&lt;/code&gt; automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design Token access&lt;/strong&gt; — your custom &lt;code&gt;createTheme()&lt;/code&gt; tokens surface in the inspector.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't features you can retrofit onto a generic visual editor. They require knowing what MUI is, how it works, and where the edge cases are.&lt;/p&gt;




&lt;h2&gt;
  
  
  What we gave up
&lt;/h2&gt;

&lt;p&gt;The SCD model has real costs. It's why most tools don't do it. We owe an honest accounting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;We don't work on every React codebase.&lt;/strong&gt; If your components are deeply entangled with SSR edge cases, or your bundler produces non-standard output, the AST layer may not parse cleanly. We document the boundaries instead of pretending they don't exist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Focus is our superpower.&lt;/strong&gt; No Vue, no Svelte, no Angular — not on the roadmap. We'd rather be the best possible tool for one ecosystem than a mediocre tool for five. We are dedicated exclusively to the React ecosystem, deeply supporting leading design systems like MUI and shadcn/ui, with expandable support for Joy UI, Ant Design, and beyond.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;We don't generate apps.&lt;/strong&gt; If you want to prompt your way to a working dashboard, use v0 or Bolt. They're genuinely good at that. We're for engineers who already have a codebase and want a canvas that respects it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;We don't host your code.&lt;/strong&gt; No CrossUI-side storage. Git operations are direct browser-to-provider. That's a feature, but it also means we can't offer cloud workspaces, team collaboration on a shared document, or any of the conveniences a hosted model enables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;We evolve alongside the ecosystem.&lt;/strong&gt; We closely follow major updates of our supported component libraries. While we prioritize empowering teams on the latest versions with robust, modern alignment, we continually evaluate expanding our backwards compatibility. If you are locked into legacy framework versions, we might not be the right tool for you — yet.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The decision
&lt;/h2&gt;

&lt;p&gt;Three honest recommendations, no false modesty:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;If you're…&lt;/th&gt;
&lt;th&gt;…use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Building a marketing site that designers need to edit&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Plasmic&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prototyping from scratch and want AI generation speed&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;v0&lt;/strong&gt; or &lt;strong&gt;Bolt&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Handing Figma files off to engineers, once&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Locofy&lt;/strong&gt; or &lt;strong&gt;Anima&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maintaining a React + MUI codebase, care about your git history, want a visual canvas that treats your code as the source of truth&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;CrossUI Studio&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Playground is free, works immediately, and doesn't require connecting a repo. Paste any React snippet and see it on the canvas.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About CrossUI Studio&lt;/strong&gt; — A visual IDE for React &amp;amp; MUI. Code and canvas stay in two-way sync on the same AST: edit code and the canvas updates live; click an element on the canvas, edit its props visually, and the code changes with a surgical one-line diff. No build, no localhost — it runs in the browser, works on your real Git repo or a local folder, with no vendor lock-in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://studio.crossui.com" rel="noopener noreferrer"&gt;Try it free → studio.crossui.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ast</category>
      <category>react</category>
      <category>scd</category>
      <category>mui</category>
    </item>
    <item>
      <title>CrossUI Web App Builder</title>
      <dc:creator>Jack Lee</dc:creator>
      <pubDate>Mon, 13 May 2019 21:46:10 +0000</pubDate>
      <link>https://dev.to/linb/crossui-builder-je4</link>
      <guid>https://dev.to/linb/crossui-builder-je4</guid>
      <description>&lt;p&gt;&lt;a href="https://crossui.com/RADGithub" rel="noopener noreferrer"&gt;https://crossui.com/RADGithub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Explore the benefits of the no code app builder&lt;br&gt;
You no longer need to hire an app developer to create an application for you. Create a fully interactive and responsive HTML5 application without writing a single line of code with CrossUI Front-end Builder. It’s much faster, easier and more fun to do app development without coding. Just choose the necessary template, modify all the elements you need and launch. Whether you need to create an interactive prototype, database management app or build a management information system, you can do it with the Cross UI app builder within several days.&lt;/p&gt;

&lt;p&gt;What you can do with CrossUI no code app builder&lt;br&gt;
If you hired a developer, you would have spent as much time explaining the concept as it took you to do it yourself with CrossUI. With CrossUI, every person who is familiar with business logic can build an application. Just make sure that your data can be stored in a database, entered with a form and displayed in common charts, tables, or rows. Our builder has an easy-to-navigate menu and a set of features that will allow you to design and build your HTML5 application within a few days. Just create what you imagine. Here are the things you can do with the CrossUI builder:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use built-in templates relevant to the type of application you want to build.&lt;/li&gt;
&lt;li&gt;Drag and drop the objects to the desired location.&lt;/li&gt;
&lt;li&gt;Use and edit 100+ UI widgets. Among them are buttons, inputs, lists, tabs, shapes, diagrams, charts and other.&lt;/li&gt;
&lt;li&gt;Create customized reusable modules.&lt;/li&gt;
&lt;li&gt;Bring in interaction by using events actions that can be easily configured.&lt;/li&gt;
&lt;li&gt;Call Remote Service EndPoint. No coding is required.&lt;/li&gt;
&lt;li&gt;Publish your app where you want, on any desktop (Linux, Windows, Mac PC/Mobile), or any website.&lt;/li&gt;
&lt;li&gt;Embed the WYSIWYG designer, our designer product, into the application you already have. The exported APIs and Events offer customization flexibility to developers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Benefits of no code apps&lt;br&gt;
Create an app without coding to quickly get custom solutions to your business needs. According to a Quick Base report, no code app builders can help save money, increase productivity, and work efficiency. Use CrossUI to save time and remain 100% focused on your business. It is especially beneficial for small businesses that don’t require complex solutions. If you need to organize inventory information, keep track of your business contacts, manage customer data, you can do it with an app, developed with an app builder specifically for your case. CrossUI front-end builder has a user-friendly dashboard and admin panel that make updates a breeze. You can entirely customize your application's behavior without writing code. Its API tools allow connecting apps to your own back-end software. The library of pre-built application elements reduce development time and accelerate production. CrossUI builder can be used for commercial projects as well as non-profit ones. If you are a student who wants to learn how to create an app with no coding, or if you have personal, not-for-profit projects, we can offer you a license at a special price. Check out our prices on the Purchase page. Keep in mind, that each license is bound to one PC only. If you are interested in reselling our products, please contact our sales department. Build an app without code which is powerful enough to support your most ambitious ideas!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3fvzbikllzka1hc663gr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3fvzbikllzka1hc663gr.png" width="680" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>design</category>
      <category>github</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
