Files
agent-skills/skills/vue-best-practices/reference/computed-properties-for-class-logic.md
Jason Woltje f5792c40be feat: Complete fleet — 94 skills across 10+ domains
Pulled ALL skills from 15 source repositories:
- anthropics/skills: 16 (docs, design, MCP, testing)
- obra/superpowers: 14 (TDD, debugging, agents, planning)
- coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth)
- better-auth/skills: 5 (auth patterns)
- vercel-labs/agent-skills: 5 (React, design, Vercel)
- antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo)
- Plus 13 individual skills from various repos

Mosaic Stack is not limited to coding — the Orchestrator and
subagents serve coding, business, design, marketing, writing,
logistics, analysis, and more.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:27:42 -06:00

122 lines
2.7 KiB
Markdown

# Use Computed Properties for Complex Class Logic
## Rule
When class bindings involve multiple conditions or complex logic, extract them into computed properties rather than writing inline expressions in templates.
## Why This Matters
- Inline class expressions quickly become unreadable with multiple conditions
- Computed properties are cached and only re-evaluate when dependencies change
- Logic in computed properties is easier to test and debug
- Keeps templates focused on structure, not logic
## Bad Code
```vue
<template>
<!-- Hard to read, error-prone -->
<div :class="{
'btn': true,
'btn-primary': type === 'primary' && !disabled,
'btn-secondary': type === 'secondary' && !disabled,
'btn-disabled': disabled,
'btn-loading': isLoading,
'btn-large': size === 'large',
'btn-small': size === 'small'
}">
{{ label }}
</div>
<!-- Even worse: string concatenation -->
<div :class="'btn btn-' + type + (disabled ? ' btn-disabled' : '') + (isLoading ? ' btn-loading' : '')">
{{ label }}
</div>
</template>
```
## Good Code
```vue
<script setup>
import { computed } from 'vue'
const props = defineProps({
type: { type: String, default: 'primary' },
size: { type: String, default: 'medium' },
disabled: Boolean,
isLoading: Boolean,
label: String
})
const buttonClasses = computed(() => ({
'btn': true,
[`btn-${props.type}`]: !props.disabled,
'btn-disabled': props.disabled,
'btn-loading': props.isLoading,
'btn-large': props.size === 'large',
'btn-small': props.size === 'small'
}))
</script>
<template>
<div :class="buttonClasses">
{{ label }}
</div>
</template>
```
## Style Bindings Too
The same principle applies to style bindings:
```vue
<script setup>
import { computed } from 'vue'
const props = defineProps({
color: String,
fontSize: Number,
isHighlighted: Boolean
})
const textStyles = computed(() => ({
color: props.color,
fontSize: `${props.fontSize}px`,
backgroundColor: props.isHighlighted ? 'yellow' : 'transparent',
fontWeight: props.isHighlighted ? 'bold' : 'normal'
}))
</script>
<template>
<span :style="textStyles">Styled text</span>
</template>
```
## Combining Static and Dynamic Classes
Use array syntax to combine static classes with computed dynamic classes:
```vue
<script setup>
import { computed } from 'vue'
const dynamicClasses = computed(() => ({
'is-active': isActive.value,
'is-disabled': isDisabled.value
}))
</script>
<template>
<!-- Static 'card' class + dynamic classes -->
<div :class="['card', dynamicClasses]">
Content
</div>
</template>
```
## References
- [Class and Style Bindings](https://vuejs.org/guide/essentials/class-and-style.html)
- [Computed Properties](https://vuejs.org/guide/essentials/computed.html)