Skip to content

Best Practices

Conditional Rendering

Always check hasContent or visible before rendering elements:

vue
<h1 v-if="titleDesign.visible && title.hasContent" :style="titleStyle">
  {{ title.value }}
</h1>

Computed Styles

Use computed properties for style objects to ensure reactivity:

vue
<script setup lang="ts">
const titleStyle = computed(() => ({
  fontSize: `${titleDesign.size}px`,
  fontFamily: titleDesign.font,
  color: (titleDesign.color as Color).hex
}));
</script>

SSR vs Client-Only Rendering

Sections use server-side rendering (SSR) — the Vue component renders to HTML on the server first, then hydrates in the browser. Browser APIs like window, document, and addEventListener are not available during SSR.

Guard browser values with typeof window:

typescript
const windowWidth = ref<number>(typeof window !== 'undefined' ? window.innerWidth : 0);

Use onMounted for client-only logic:

Code inside onMounted only runs in the browser after hydration. Use it for event listeners, DOM measurements, animations, and any browser-API-dependent setup:

typescript
import { onMounted, onBeforeUnmount } from 'vue';

onMounted(() => {
  initializeSlider();
  window.addEventListener('resize', onResize);
});

onBeforeUnmount(() => {
  window.removeEventListener('resize', onResize);
});

General rule: Keep <script setup> top-level code SSR-safe — composables, computed properties, and reactive refs with safe defaults. Move all browser-specific logic into onMounted. If a piece of UI should only render on the client, guard it with a ref that flips in onMounted:

vue
<script setup lang="ts">
import { ref, onMounted } from 'vue';

const isMounted = ref(false);
onMounted(() => { isMounted.value = true; });
</script>

<template>
  <div v-if="isMounted">
    <!-- Client-only content -->
  </div>
</template>