How does Mitosis compile components to different frameworks?

Updated

Mitosis is a tool from Builder.io that lets you write a component once in a JSX-like syntax and compile it into native code for React, Vue, Svelte, Angular, Qwik, and other frameworks. You get a single source of truth for a design system, and the compiler handles the framework-specific translation. This page explains the mechanism, using the official example as a reference.

The core idea: one source, many outputs

Instead of maintaining separate component libraries per framework, you write the component in mitosis.jsx using imports from @builder.io/mitosis. The compiler then reads that file and emits equivalent components in each target framework. The logic (state, props, event handlers) and styles are preserved, but the syntax is rewritten to match each framework's conventions.

What the input looks like

The source component uses JSX plus Mitosis primitives such as useState:

import { useState } from "@builder.io/mitosis";

export default function MyComponent(props) {
  const [name, setName] = useState("Steve");
  return (
    <div>
      <input
        css={{ color: "red" }}
        value={name}
        onChange={(event) => setName(event.target.value)}
      />
      Hello! I can run natively in React, Vue, Svelte, Qwik, and many more frameworks!
    </div>
  );
}

Two things matter here: the reactive state (name / setName) and the inline css object. Both need to survive compilation into each framework's own idioms.

How the compiler translates it

The compiler parses the JSX and maps Mitosis constructs onto each target's equivalents:

  • State — useState becomes ref in Vue, a class field in Angular, a let binding in Svelte, and useStore in Qwik.
  • Event handlers — onChange becomes @change in Vue, bind:value in Svelte, onChange$ in Qwik, and so on.
  • Styles — the css={{ color: "red" }} object becomes a scoped class or inline style appropriate to the framework.
  • Markup — JSX is rewritten to templates (Vue, Angular, Svelte) or kept as JSX/TSX (React, Qwik).

The same component in each framework

The example shows one source producing five different outputs. The behavior is identical; only the syntax differs.

Framework State mechanism Event binding Style handling
React useState onChange inline css
Vue ref @change <style scoped>
Angular class field template binding styles: [...]
Svelte let bind:value <style>
Qwik useStore onChange$ useStylesScoped$

For example, the Vue output uses ref("Steve") and a scoped .input { color: red; } rule, while the Qwik output uses useStore({ name: "Steve" }) and a scoped class name generated by useStylesScoped$. The Angular output declares name = "Steve" as a class property and moves the style into the component's styles array.

Why this matters for design systems

If you maintain a component library that must work across multiple frameworks, writing and testing each version separately multiplies the maintenance cost. Mitosis lets you keep one canonical implementation and regenerate the rest. The trade-off is that you work within Mitosis's supported subset of JSX, so very framework-specific features may not translate cleanly. For shared, presentational components and design-system primitives, that subset is usually enough.

Getting started

The site offers a Get Started path and a Playground where you can paste a Mitosis component and inspect the generated output for each framework. The Playground is the fastest way to verify how a given construct compiles before committing to it in a real project.