Skip to content

Instantly share code, notes, and snippets.

@supermensa
Created April 21, 2023 17:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save supermensa/89fb9e2d23bd6fd9a54374cd30d91813 to your computer and use it in GitHub Desktop.
Save supermensa/89fb9e2d23bd6fd9a54374cd30d91813 to your computer and use it in GitHub Desktop.
Renderless components
https://vuejs.org/guide/components/slots.html#renderless-components
The recommendation is to use composables when reusing pure logic, and use components when reusing both logic and visual layout.
In Vue 3, a renderless component is a reusable and flexible component that focuses on providing functionality without prescribing how the final UI should look. The term "renderless" comes from the fact that these components don't render any markup or styles themselves. Instead, they expose their functionality through scoped slots, which allows the parent component to dictate how the UI should be rendered.
The primary motivation behind renderless components is to promote reusability and separation of concerns. By decoupling the logic and presentation, these components can be easily shared across projects or within a team without being restricted to specific styles or design systems.
To create a renderless component in Vue 3, you'll typically use the following concepts:
1. Composition API: Vue 3 introduced the Composition API, which provides a more flexible and composable way to organize component logic. Renderless components often take advantage of this API to expose their functionality.
2. Scoped slots: Scoped slots are a way to pass data from the renderless component to the parent component. This enables the parent to determine the final rendered output while utilizing the functionality provided by the renderless component.
Here's an example of a simple renderless component that manages a counter:
```javascript
// CounterLogic.vue
<template>
<slot
:count="count"
:increment="increment"
:decrement="decrement"
></slot>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
function increment() {
count.value++;
}
function decrement() {
count.value--;
}
return {
count,
increment,
decrement,
};
},
};
</script>
```
To use this renderless component, you can create a parent component that leverages the scoped slot to define the UI:
```javascript
// ParentComponent.vue
<template>
<CounterLogic v-slot="{ count, increment, decrement }">
<div>
<button @click="decrement">-</button>
<span>{{ count }}</span>
<button @click="increment">+</button>
</div>
</CounterLogic>
</template>
<script>
import CounterLogic from './CounterLogic.vue';
export default {
components: {
CounterLogic,
},
};
</script>
```
In this example, the `CounterLogic` renderless component handles the counter's state and exposes the count, increment, and decrement functions through the scoped slot. The parent component then takes control of how the UI is rendered while utilizing the functionality provided by the renderless component.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment