DEV Community

Cover image for Vue v-slot to React: How does VuReact handle it?
Ryan John
Ryan John

Posted on • Originally published at vureact.top

Vue v-slot to React: How does VuReact handle it?

VuReact is a compiler for migrating from Vue to React — and for writing React with Vue syntax. In this article, we dive straight into the core: how Vue's common v-slot directive is compiled into React code by VuReact.

Before We Start

To keep the examples easy to read, this article follows two simple conventions:

  1. All Vue and React snippets focus on core logic only, with full component wrappers and unrelated configuration omitted.
  2. The discussion assumes you are already familiar with Vue 3's v-slot directive usage.

Compilation Mapping

v-slot / #: Basic slot usage

v-slot (shorthand #) is Vue's directive for defining and using slots, enabling content distribution and reuse in components.

Default slot

  • Vue
<!-- Parent component -->
<MyComponent>
  <template #default>
    <p>Default slot content</p>
  </template>
</MyComponent>

<!-- Or shorthand -->
<MyComponent>
  <p>Default slot content</p>
</MyComponent>
Enter fullscreen mode Exit fullscreen mode
  • Compiled React
// Parent component
<MyComponent>
  <p>Default slot content</p>
</MyComponent>
Enter fullscreen mode Exit fullscreen mode

As the example shows, Vue's default slot is directly compiled into React's children. VuReact adopts a children compilation strategy, converting template slots into React's standard children passing mechanism. This fully preserves Vue's default slot semantics — passing content as child elements to the component.

The key characteristics of this compilation approach are:

  1. Semantic consistency: Fully simulates Vue's default slot behavior by implementing content distribution
  2. React-native support: Uses React's standard children mechanism with no additional adaptation needed
  3. Simplified syntax: Vue's <template #default> is simplified to directly passing child elements
  4. Performance optimization: Uses React's native mechanism directly with zero runtime overhead

Named slots

Vue supports multiple named slots for more flexible content distribution.

Basic named slots

  • Vue
<!-- Parent component -->
<Layout>
  <template #header>
    <h1>Page Title</h1>
  </template>

  <template #main>
    <p>Main content area</p>
  </template>

  <template #footer>
    <p>Footer information</p>
  </template>
</Layout>
Enter fullscreen mode Exit fullscreen mode
  • Compiled React
// Parent component
<Layout 
  header={<h1>Page Title</h1>}
  main={<p>Main content area</p>}
  footer={<p>Footer information</p>}
/>
Enter fullscreen mode Exit fullscreen mode

As the example shows, Vue's named slots are compiled into React props. VuReact adopts a props compilation strategy, converting named slots into component props. This fully preserves Vue's named slot semantics — distinguishing different slot content through different prop names.


Scoped slots

Vue's scoped slots allow child components to pass data back to parent components, enabling more flexible render control.

Basic scoped slots

  • Vue
<!-- Parent component -->
<DataList :items="users">
  <template #item="slotProps">
    <div class="user-item">
      <span>{{ slotProps.user.name }}</span>
      <span>{{ slotProps.user.age }} years old</span>
    </div>
  </template>
</DataList>

<!-- Child component DataList.vue -->
<template>
  <ul>
    <li v-for="item in props.items" :key="item.id">
      <slot name="item" :user="item"></slot>
    </li>
  </ul>
</template>
Enter fullscreen mode Exit fullscreen mode
  • Compiled React
// Parent component
<DataList 
  items={users}
  item={(slotProps) => (
    <div className="user-item">
      <span>{slotProps.user.name}</span>
      <span>{slotProps.user.age} years old</span>
    </div>
  )}
/>

// Child component DataList.jsx
function DataList(props) {
  return (
    <ul>
      {props.items.map((itemData) => (
        <li key={itemData.id}>
          {props.item?.({ user: itemData })}
        </li>
      ))}
    </ul>
  );
}
Enter fullscreen mode Exit fullscreen mode

As the example shows, Vue's scoped slots are compiled into React function props. VuReact adopts a function props compilation strategy, converting scoped slots into function props that receive parameters. This fully preserves Vue's scoped slot semantics — the child component passes data to the parent through function calls, and the parent receives data and renders via function parameters.


Dynamic slot names

Vue supports dynamic slot names for more flexible slot selection.

  • Vue
<BaseLayout>
  <template #[dynamicSlotName]>
    Dynamic slot content
  </template>
</BaseLayout>
Enter fullscreen mode Exit fullscreen mode
  • Compiled React
<BaseLayout 
  {...{ [dynamicSlotName]: "Dynamic slot content" }}
/>
Enter fullscreen mode Exit fullscreen mode

Compilation strategy:

  1. Computed property name: Uses the object computed property syntax { [key]: value }
  2. Object spread: Applies to the component via the object spread syntax
  3. Runtime processing: Dynamic slot names need to be determined at runtime

Slot fallback content

Vue supports providing default content in slot definitions, displayed when the parent component does not provide slot content.

  • Vue
<!-- Child component Button.vue -->
<template>
  <button class="btn">
    <slot>
      <span>Default button text</span>
    </slot>
  </button>
</template>
Enter fullscreen mode Exit fullscreen mode
  • Compiled React
// Child component Button.jsx
function Button(props) {
  return (
    <button className="btn">
      {props.children || <span>Default button text</span>}
    </button>
  );
}
Enter fullscreen mode Exit fullscreen mode

Fallback content handling rules:

  1. children check: Checks whether children exists
  2. Default value rendering: Renders fallback content when children is falsy
  3. React compatible: Uses React's standard conditional rendering pattern

Compilation strategy summary

VuReact's v-slot compilation strategy demonstrates a complete slot system conversion capability:

  1. Default slots: Converted to React's children
  2. Named slots: Converted to component props
  3. Scoped slots: Converted to function props
  4. Dynamic slots: Supports dynamic slot names
  5. Fallback content: Supports slot default content

Slot type mapping table:

Vue slot type React equivalent Description
Default slot children As child elements of the component
Named slot prop As a property of the component
Scoped slot function prop As a function property that receives parameters
Dynamic slot computed property Uses object computed property syntax

Performance optimization strategy:

  1. Static slot optimization: Static slot content is compiled into static JSX
  2. Function caching: For scoped slots, render functions are intelligently cached
  3. On-demand generation: The most minimal code is generated based on actual usage
  4. Type inference: Slot type definitions are intelligently inferred

VuReact's compilation strategy ensures a smooth migration from Vue to React. Developers do not need to manually rewrite slot logic. The compiled code preserves Vue's semantics and flexibility while following React's component design patterns, keeping the migrated application fully capable of content distribution.

Related Links

Top comments (0)