Styling
This boilerplate uses Tailwind CSS v4 for styling, providing a utility-first approach with excellent developer experience and built-in dark mode support.
Overview
The styling system includes:
- Tailwind CSS v4 - Latest version with improved performance
- Dark/light mode - Automatic theme switching with system preference detection
- Custom design tokens - Centralized color and spacing configuration
- Typography plugin - Beautiful prose styles for content
- Auto-complete - Full IntelliSense support in your editor
Configuration
Tailwind configuration
The main Tailwind CSS file is located at app/assets/css/tailwind.css:
@import 'tailwindcss';
/* Your custom styles here */
Nuxt configuration
Tailwind is integrated via the Vite plugin in nuxt.config.ts:
import tailwindcss from '@tailwindcss/vite'
export default defineNuxtConfig({
css: ['~/assets/css/tailwind.css'],
vite: {
plugins: [tailwindcss()],
},
})
Dark mode
Dark mode is implemented using @nuxtjs/color-mode with Tailwind's dark mode support.
Color mode configuration
export default defineNuxtConfig({
colorMode: {
preference: 'system', // system, dark, or light
classSuffix: '', // Empty for Tailwind compatibility
},
})
Using dark mode in components
Tailwind's dark: variant applies styles in dark mode:
<template>
<div class="bg-white dark:bg-black text-black dark:text-white">This adapts to the theme</div>
</template>
Theme switcher
The boilerplate includes a theme switcher component at app/components/header/ThemeSwitcher.vue:
<script setup>
const colorMode = useColorMode()
const setTheme = theme => {
colorMode.preference = theme
}
</script>
<template>
<DropdownMenu>
<DropdownMenuItem @click="setTheme('light')"> Light </DropdownMenuItem>
<DropdownMenuItem @click="setTheme('dark')"> Dark </DropdownMenuItem>
<DropdownMenuItem @click="setTheme('system')"> System </DropdownMenuItem>
</DropdownMenu>
</template>
Accessing color mode in script
<script setup>
const colorMode = useColorMode()
// Get current theme
console.log(colorMode.value) // 'light', 'dark', or 'system'
// Check if dark mode is active
const isDark = computed(() => colorMode.value === 'dark')
// Set theme
colorMode.preference = 'dark'
</script>
Design system
The boilerplate uses CSS variables for theming, defined in app/assets/css/tailwind.css:
@theme {
/* Color palette */
--color-background: 0 0% 100%;
--color-foreground: 240 10% 3.9%;
--color-primary: 240 5.9% 10%;
--color-muted: 240 4.8% 95.9%;
/* Dark mode colors */
@dark {
--color-background: 240 10% 3.9%;
--color-foreground: 0 0% 98%;
--color-primary: 0 0% 98%;
--color-muted: 240 3.7% 15.9%;
}
}
Using design tokens
<template>
<div class="bg-background text-foreground">
<h1 class="text-primary">Title</h1>
<p class="text-muted-foreground">Description</p>
</div>
</template>
Common utility classes
Layout
<!-- Flexbox -->
<div class="flex items-center justify-between gap-4">
<!-- Grid -->
<div class="grid grid-cols-3 gap-4">
<!-- Container with max width -->
<div class="base-container"><!-- Custom class defined in the boilerplate --></div>
</div>
</div>
Spacing
<!-- Padding -->
<div class="p-4">
<!-- All sides -->
<div class="px-4 py-8">
<!-- Horizontal and vertical -->
<!-- Margin -->
<div class="m-4">
<!-- All sides -->
<div class="mb-8">
<!-- Bottom only -->
<!-- Gap -->
<div class="flex gap-4"><!-- Space between flex items --></div>
</div>
</div>
</div>
</div>
Typography
<!-- Font size -->
<h1 class="text-4xl font-bold">Heading</h1>
<p class="text-base">Body text</p>
<span class="text-sm text-muted-foreground">Caption</span>
<!-- Font weight -->
<span class="font-light">Light</span>
<span class="font-normal">Normal</span>
<span class="font-semibold">Semibold</span>
<span class="font-bold">Bold</span>
Colors
<!-- Text colors -->
<p class="text-foreground">Primary text</p>
<p class="text-muted-foreground">Secondary text</p>
<p class="text-destructive">Error text</p>
<!-- Background colors -->
<div class="bg-background">
<div class="bg-muted">
<div class="bg-primary text-primary-foreground"></div>
</div>
</div>
Borders and shadows
<!-- Borders -->
<div class="border border-border rounded-lg">
<!-- Shadows -->
<div class="shadow-sm">
<!-- Small shadow -->
<div class="shadow-md">
<!-- Medium shadow -->
<div class="shadow-lg"><!-- Large shadow --></div>
</div>
</div>
</div>
Responsive design
<!-- Mobile-first approach -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
<!-- 1 column on mobile, 2 on tablet, 3 on desktop -->
</div>
<!-- Responsive padding -->
<div class="p-4 md:p-8 lg:p-12"></div>
Custom CSS
Adding custom utilities
Add custom utilities to app/assets/css/tailwind.css:
@import 'tailwindcss';
@layer utilities {
.glass-effect {
@apply bg-background/80 backdrop-blur-lg;
}
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
}
Then use them in your components:
<template>
<div class="glass-effect">Glassmorphism effect</div>
</template>
Custom base styles
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
Pre-defined custom classes
The boilerplate includes some helpful custom classes:
base-container
A responsive container with consistent padding:
<template>
<div class="base-container">
<!-- Content with responsive padding and max-width -->
</div>
</template>
Definition:
.base-container {
@apply container mx-auto px-4 sm:px-6 lg:px-8;
}
Typography plugin
The boilerplate includes @tailwindcss/typography for styling markdown content:
<template>
<article class="prose dark:prose-invert max-w-none">
<ContentRenderer :value="post" />
</article>
</template>
The prose class provides beautiful typography styles for:
- Headings
- Paragraphs
- Lists
- Blockquotes
- Code blocks
- Tables
Customizing prose styles
<template>
<!-- Adjust max width -->
<article class="prose prose-lg max-w-4xl">
<!-- Modify specific elements -->
<article class="prose prose-headings:font-semibold prose-a:text-primary">
</template>
Best practices
Use semantic color names
<!-- Good: Semantic naming -->
<div class="bg-primary text-primary-foreground">
<!-- Avoid: Direct color values -->
<div class="bg-blue-500 text-white"></div>
</div>
Utilize dark mode properly
<!-- Good: Specify both modes -->
<div class="bg-white dark:bg-black">
<!-- Avoid: Only light mode -->
<div class="bg-white"></div>
</div>
Keep utilities in template
<!-- Good: Utilities in template -->
<template>
<div class="flex items-center gap-4 p-4">
</template>
<!-- Avoid: Custom CSS for simple layouts -->
<style>
.my-container {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
}
</style>
Use @apply sparingly
Only use @apply for complex, reusable patterns:
/* Good: Complex reusable component */
.button-primary {
@apply px-4 py-2 bg-primary text-primary-foreground rounded-md
hover:bg-primary/90 transition-colors;
}
/* Avoid: Simple utilities */
.text-center-class {
@apply text-center;
}
Animations
Tailwind provides built-in animations. The boilerplate also uses tw-animate-css for additional animations:
<template>
<!-- Fade in -->
<div class="animate-in fade-in duration-500">
<!-- Slide in -->
<div class="animate-in slide-in-from-bottom-4 duration-300">
<!-- Spin (loading indicator) -->
<div class="animate-spin">
</template>
Debugging
View applied classes
Use browser DevTools to inspect elements and see which Tailwind classes are applied.
Tailwind IntelliSense
Install the Tailwind CSS IntelliSense extension for VS Code to get:
- Autocomplete for class names
- Linting for invalid classes
- Hover previews of CSS values
- Color decorators
Reference
- Tailwind CSS documentation
- Tailwind CSS v4 blog post
- @nuxtjs/color-mode documentation
- Tailwind CSS IntelliSense