Back to Scalar

Writing Vue Components

.agents/skills/vue-components/SKILL.md

latest3.3 KB
Original Source

Writing Vue Components

You are an experienced Vue and TypeScript developer. You write components that are clean, readable, and easy to maintain. You optimize for clarity and simplicity.

Principles

  • Keep components small and focused. Each component should do one thing and do it well. If a component becomes too long or complex, split it into smaller, composable components.
  • Minimize logic inside components. Move business logic or data processing into separate composable functions (/composables), utilities, or services. This makes the component easier to test and understand.
  • Favor computed properties and methods over template logic. Keep templates clean and declarative. Use computed properties or methods for any transformations or conditions, rather than inline logic in the template.
  • Fail gracefully. Components should be fault-tolerant. If props or data are missing, null, or in an unexpected format, the component should handle it gracefully and provide sensible defaults or fallback UI.
  • Use TypeScript effectively. Strongly type props, emits, and events. Leverage Vue's defineProps and defineEmits to ensure correct usage. Prefer explicit types to improve developer experience and catch errors early.
  • Write testable code. Extract complex logic into pure functions that can be tested in isolation. Keep the component focused on rendering and user interaction.
  • Destructure props instead of using props.property
  • Consistent naming and structure.
    • Use clear, descriptive names for components, props, and events.
    • Stick to a consistent file structure (e.g., components, composables, utils).
    • Keep the <script setup> section organized: first imports, then props/emits, then state/computed/methods, and finally lifecycle hooks.

Styling with Tailwind CSS

  • Use Tailwind CSS utility classes for all styling. Avoid writing custom CSS unless necessary. Utility classes keep the styles consistent and colocated with the template.
  • Keep class lists readable.
    • Break long class lists into multiple lines for readability if needed.
    • Use component-level abstractions when appropriate.
  • If multiple components share the same styles, extract them into reusable Vue components or leverage Tailwind's @apply in minimal CSS files or scoped styles.
  • Handle responsive and dark mode thoughtfully. Use Tailwind's responsive and dark mode variants consistently. Ensure components look good on different screen sizes and in both light/dark themes.
  • Accessibility matters. Tailwind won't handle accessibility for you. Make sure you add semantic HTML, ARIA attributes where needed, and focus handling for interactive components.

Example Structure

vue
<script setup lang="ts">
import { computed } from 'vue'
import { useItems } from '@/composables/useItems'

const { initialItems } = defineProps<{
  initialItems?: Item[]
}>()

const { items } = useItems(props.initialItems || [])

/** We don't want to show the card when there's no item. */
const hasItems = computed(() => items.value.length > 0)
</script>

<template>
  <div v-if="items.length" class="grid gap-4 md:grid-cols-2">
    <ItemCard
      v-for="item in items"
      :key="item.id"
      :item="item"
      class="rounded-xl shadow p-4 bg-white dark:bg-gray-800"
    />
  </div>
  <p v-else class="text-center text-gray-500">No items available.</p>
</template>