renderless-components
Teaches the renderless component pattern for logic-only Vue components. Use when you want to encapsulate behavior without dictating markup, letting consumers control rendering via scoped slots.
What this skill does
# Renderless Components
## Table of Contents
- [When to Use](#when-to-use)
- [When NOT to Use](#when-not-to-use)
- [Instructions](#instructions)
- [Details](#details)
- [Source](#source)
Renderless components are a pattern in Vue that **separates the logic of a component from its presentation**. The pattern provides a way to encapsulate functionality without _dictating the visual representation of the component_. In other words, a renderless component focuses solely on the logic and behavior, while leaving the rendering to the parent component.
Renderless components are particularly useful when we need to create reusable logic that can be applied to different UI implementations. By abstracting the logic into a renderless component, we can easily reuse it in various contexts without duplicating code.
## When to Use
- Use this when you need to reuse logic across components with completely different visual representations
- This is helpful for providing a component-based API in a component library
## When NOT to Use
- When composables achieve the same logic reuse without extra component nesting (Vue 3+)
- When the renderless component wraps trivial logic that a simple function or composable handles more clearly
- When the scoped slot API becomes harder to understand than a direct composable return value
## Instructions
- Create a component that provides data and methods through a single `<slot>` with scoped slot props
- Use `v-slot` destructuring in parent components to access the provided data and methods
- Prefer composables over renderless components in Vue 3 to avoid extra component nesting
- Use renderless components when you want template-level composition or a component-based API
## Details
### Toggle, toggle, toggle
Imagine you have a toggle UI element that needs to be used in different parts of your application, but each instance may have a different visual representation. Some toggles might be displayed as buttons, while others might be checkboxes or switches.
We could just create three different toggle components, however, we can observe that each toggle element has the same logic and behavior. Each toggle has an inactive and active state that's being tracked with a component data property (e.g. `checked`). When a toggle is clicked, its component state is switched from inactive to active and vice versa (i.e. `checked = !checked`).
Right away, we can see that we can create a more reusable pattern by extracting the common logic and behavior in such a way that we don't have to repeatedly define the state and toggle methods in each individual toggle component. This is a great case to use [composables](/vue/composables) since composables will allow us to encapsulate and share the common stateful logic across the different toggle components.
**useCheckboxToggle**:
```js
import { ref } from "vue";
export function useCheckboxToggle() {
const checkbox = ref(false);
const toggleCheckbox = () => {
checkbox.value = !checkbox.value;
};
return {
checkbox,
toggleCheckbox,
};
}
```
With this composable, we can now use the `useCheckboxToggle()` function in our various toggle components to share the common state and toggle logic.
However, there's another approach we can take that leverages Vue's slot mechanism — the **renderless component** pattern.
### The Renderless Component
A renderless component in Vue is a component that encapsulates logic and provides data to its children via **scoped slots**, without rendering any markup of its own. The parent component decides how the data is presented.
Here's a simple renderless `Toggle` component:
```html
<script setup>
import { ref } from "vue";
const checked = ref(false);
const toggle = () => {
checked.value = !checked.value;
};
</script>
<template>
<slot :checked="checked" :toggle="toggle"></slot>
</template>
```
The `Toggle` component doesn't render any HTML of its own. It only provides data (`checked` and `toggle`) through a scoped slot. The parent component can now consume this data and render whatever UI it wants.
**Using the renderless Toggle as a button:**
```html
<template>
<Toggle v-slot="{ checked, toggle }">
<button @click="toggle">
{{ checked ? "ON" : "OFF" }}
</button>
</Toggle>
</template>
```
**Using the renderless Toggle as a checkbox:**
```html
<template>
<Toggle v-slot="{ checked, toggle }">
<label>
<input type="checkbox" :checked="checked" @change="toggle" />
{{ checked ? "Checked" : "Unchecked" }}
</label>
</Toggle>
</template>
```
**Using the renderless Toggle as a switch:**
```html
<template>
<Toggle v-slot="{ checked, toggle }">
<div
class="switch"
:class="{ active: checked }"
@click="toggle"
>
<div class="switch-handle"></div>
</div>
</Toggle>
</template>
```
In all three cases, the same `Toggle` renderless component provides the toggle logic, but the rendering is entirely different!
### Composables vs. Renderless Components
Both composables and renderless components achieve the goal of reusing logic across components. However, there are some differences:
**Composables:**
- Logic is encapsulated in a regular JavaScript function.
- Can be used directly in `<script setup>` or `setup()`.
- Don't involve any additional component layers.
**Renderless components:**
- Logic is encapsulated in a Vue component.
- Use scoped slots to pass data to children.
- Add an extra component layer in the template.
In general, composables are the preferred approach in Vue 3 since they don't add extra component nesting. However, renderless components can be useful when you want to provide a component-based API (e.g., in a component library) or when you need template-level composition.
## Source
- [patterns.dev/vue/renderless-components](https://patterns.dev/vue/renderless-components)
### References
- [Renderless Components | Vue Documentation](https://vuejs.org/guide/components/slots.html#renderless-components)
- [Composables | Vue Documentation](https://vuejs.org/guide/reusability/composables.html)
Related in Design
contribute
IncludedLocal-only OSS contribution command center. Auto-refreshes the user's in-flight PR and issue state on invoke so conversations start with full context — no need to brief Claude on what's in flight. Helps the user find issues to contribute to on GitHub, builds per-repo dossiers of what each upstream expects (CLA, DCO, branch convention, AI policy, draft-first, review bots, issue templates), runs deterministic gates before any external action so AI-assisted contributions don't reach maintainers as slop. State is markdown-only: candidate files at ~/.contribute-system/candidates/, repo dossiers at ~/.contribute-system/research/, append-only event log at ~/.contribute-system/log.jsonl. No database, no cloud calls. Use when the user asks about their PRs / issues / contributions, wants to find new work to take on, claim an issue, build/refresh a repo's dossier, or draft a Design Issue or PR. Trigger with "/contribute", "what's my PR status", "find a contribution", "claim issue X", "draft a Design Issue for Y", "refresh dossier for Z".
architectural-analysis
IncludedUser-triggered deep architectural analysis of a codebase or scoped subtree across eight modes — information architecture, data flow, integration points, UI surfaces, interaction patterns, data model, control flow, and failure modes. This skill should be used when the user asks to "diagram this codebase," "map the architecture," "show the data flow," "give me an ERD," "trace control flow," "find the integration points," "verify the layout pattern," "audit the UX architecture," or any similar request whose primary deliverable is mermaid diagrams plus cited reports under docs/architecture/. Dispatches haiku/sonnet sub-agents in parallel for per-mode exploration, then verifies every citation mechanically before any node lands in a diagram. Not for one-off prose explanations of code (use code-explanation) or for high-level system design from scratch (use system-design).
mcp
IncludedModel Context Protocol (MCP) server development and tool management. Languages: Python, TypeScript. Capabilities: build MCP servers, integrate external APIs, discover/execute MCP tools, manage multi-server configs, design agent-centric tools. Actions: create, build, integrate, discover, execute, configure MCP servers/tools. Keywords: MCP, Model Context Protocol, MCP server, MCP tool, stdio transport, SSE transport, tool discovery, resource provider, prompt template, external API integration, Gemini CLI MCP, Claude MCP, agent tools, tool execution, server config. Use when: building MCP servers, integrating external APIs as MCP tools, discovering available MCP tools, executing MCP capabilities, configuring multi-server setups, designing tools for AI agents.
react-native-skia
IncludedDesign, build, debug, and optimise high-polish animated graphics in React Native or Expo using @shopify/react-native-skia, Reanimated, and Gesture Handler. Use when the user wants canvas-driven UI, shaders, paths, rich text, image filters, sprite fields, Skottie, video frames, snapshots, web CanvasKit setup, or performance tuning for custom motion-heavy elements such as loaders, hero art, cards, charts, progress indicators, particle systems, or gesture-driven surfaces. Also use when the user asks for fluid, glow, glass, blob, parallax, 60fps/120fps, or GPU-friendly animated effects in React Native, even if they do not explicitly say "Skia". Do not use for ordinary form/layout work with standard views.
plaid
IncludedProduct Led AI Development — guides founders from idea to launched product. Six capabilities: Idea (discover a product idea), Validate (pressure-test the idea against fatal flaws, problem reality, competition, and 2-week MVP feasibility), Plan (vision intake + document generation), Design (translate image references into a design.md spec), Launch (go-to-market strategy), and Build (roadmap execution). Use when someone says "PLAID", "plaid idea", "help me find an idea", "product idea", "idea from my business", "idea from my expertise", "plaid validate", "validate my idea", "pressure-test", "is this idea good", "find fatal flaws", "validate the problem", "plan a product", "define my vision", "generate a PRD", "product strategy", "plaid design", "design from image", "translate image to design", "create design.md", "extract design tokens", "plaid launch", "go-to-market", "launch plan", "GTM strategy", "launch playbook", "plaid build", "build the app", "start building", or "execute the roadmap".
nextjs-framer-motion-animations
IncludedAdds production-safe Motion for React or Framer Motion animations to Next.js apps, including reveal, hover and tap micro-interactions, whileInView, stagger, AnimatePresence, layout and layoutId transitions, reorder, scroll-linked UI, and lightweight route-content transitions. Use when the user asks to add, refactor, or debug Motion or Framer Motion in App Router or Pages Router codebases, especially around server/client boundaries, reduced motion, LazyMotion, bundle size, hydration, or route transitions. Avoid for GSAP-style timelines, WebGL or 3D scenes, heavy scroll storytelling, or CSS-only effects unless Motion is explicitly requested.