Building Headless Components in Vue — The Right Way

Youssef Abdulaziz
2025-05-30T17:04:20Z
Reusable UI components often break once you change the design. Solution? Go headless.
A headless component:
"Exposes data & logic (but no styling)"
"Lets you plug in any markup/UX you want"
"Keeps behavior testable and DRY"
Example: a headless dropdown:
const useDropdown = () => {
const isOpen = ref(false)
const toggle = () => isOpen.value = !isOpen.value
return { isOpen, toggle }
}
<template>
<button @click="toggle">Toggle</button>
<div v-if="isOpen"><slot /></div>
</template>
Benefits:
"📦 Easy to theme"
"✅ Easier snapshot testing"
"🧠 Decouples logic from layout"
This is what libraries like Radix and Headless UI follow. You can build your own system for any internal tools.