vuejs / vuejs/docs

Add docs for renderless components

Open
#1,331 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

cookbook
Dominant language
Vue
Stars
3.2k
Forks
5k
Avg merge
14d 17h
Merged PRs (30d)
1

Description

With the arrival of the composition API, renderless components have become a bit less useful—IMO, composition functions are more versatile, easier to author, and easier to consume than renderless components.

That said, renderless components are still useful in some scenarios, and there are a few tricks to setting them up in Vue 3. Proper docs would explain the use case for renderless components, and have code examples for implementation in Vue. We can look to the React render props docs for inspiration.

There's also a question of where these docs should go. They definitely fit in with the Reusability & Composition section, but could also fit as one of the last guides in the Components In-Depth section.

I'll draft these docs in the near future, but meanwhile, below is some example code for anyone who might be looking. Here's an SFC playground for it.

Couple things to note in the code below:

  • It's now possible to make renderless components without render functions, by rendering a slot as the only element in a Vue template. This wasn't possible in Vue 2, which forced you to use render functions.
  • You can still use render functions to make renderless components, and the experience is improved by the setup function. Write all your component logic in setup with the composition API, then return your render function from setup at the end.
  • Render functions are not compatible with script setup, as far as I can tell. Probably not that much of a downside, since people using render functions are usually writing components in plain .js or .ts files instead of .vue files.

Rendering a normal slot with a Vue template

<!-- Renderless_NormalSlot_Template.vue -->
<script setup>
import { onMounted, onBeforeUnmount } from 'vue'

const clickEffect = () => console.log('Page was clicked!')

onMounted(() => document.addEventListener('click', clickEffect))
onBeforeUnmount(() => document.removeEventListener('click', clickEffect))
</script>

<template>
  <slot></slot>
</template>

Rendering a scoped slot with a Vue template

<!-- Renderless_ScopedSlot_Template.vue -->
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'

const count = ref(0)
const clickEffect = () => count.value++

onMounted(() => document.addEventListener('click', clickEffect))
onBeforeUnmount(() => document.removeEventListener('click', clickEffect))
</script>

<template>
  <slot :count="count"></slot>
</template>

Rendering a normal slot with a render function returned from setup

<!-- Renderless_NormalSlot_RenderFn.vue -->
<script>
import { onMounted, onBeforeUnmount } from 'vue'
  
export default {
  setup (props, { slots }) {
    const clickEffect = () => console.log('Page was clicked by normal slot render function')

    onMounted(() => document.addEventListener('click', clickEffect))
    onBeforeUnmount(() => document.removeEventListener('click', clickEffect))
    
    return slots.default
  }
}
</script>

Rendering a scoped slot with a render function returned from setup

<!-- Renderless_NormalSlot_RenderFn.vue -->
<script>
import { ref, onMounted, onBeforeUnmount } from 'vue'
  
export default {
  setup (props, { slots }) {
    const count = ref(0)
    const clickEffect = () => count.value++

    onMounted(() => document.addEventListener('click', clickEffect))
    onBeforeUnmount(() => document.removeEventListener('click', clickEffect))
    
    return () => slots.default({ count: count.value })
  }
}
</script>

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the issue's Renderless_NormalSlot_Template.vue, Renderless_ScopedSlot_Template.vue, and render-function examples, along with the linked SFC playground. Decide whether the page belongs in Reusability & Composition or Components In-Depth, then document the use case and Vue 3 template and setup-based patterns with working examples.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
documentation
Issue type
Documentation
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.