DEV Community

Cover image for Building Headless Components in Vue — The Right Way
Youssef Abdulaziz
Youssef Abdulaziz

Posted on

Building Headless Components in Vue — The Right Way

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 }
}
Enter fullscreen mode Exit fullscreen mode
<template>
  <button @click="toggle">Toggle</button>
  <div v-if="isOpen"><slot /></div>
</template>
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (2)

Collapse
 
brooks-rockett profile image
Brooks Rockett

Makes sense, but where do you add the styling afterward, assuming you’re using something inline like Tailwind?

Collapse
 
sem1colons profile image
Youssef Abdulaziz

I would use Tailwind as a personal preference and a strong recommendation , but the point is you're free to use the same functionality with multiple markups and styles (Tailwind, SCSS, CSS modules, CSS in JS, etc...).