Customization
Styling Guide
Methodology
Vextro follows a Tailwind-first approach. Use utility classes in templates for layout, spacing, colors, and typography. Reserve scoped <style> blocks for patterns that Tailwind cannot express.
When to Use Tailwind
Use Tailwind utility classes for:
- Layout:
flex,grid,items-center,justify-between - Spacing:
p-4,gap-3,mt-2,mx-auto - Colors:
text-fg,bg-surface,border-edge,text-primary - Typography:
text-sm,font-medium,tracking-tight - Responsive:
sm:flex,lg:grid-cols-3 - States:
hover:bg-surface-emphasis,focus-visible:ring-2
<div class="flex items-center gap-3 p-4 bg-surface border border-edge rounded-lg">
<span class="text-fg font-medium">Title</span>
<span class="text-fg-muted text-sm">Description</span>
</div> When to Use Scoped CSS
Keep scoped <style> blocks for patterns Tailwind cannot handle:
:global()selectors for cross-component targeting in Astro- Complex pseudo-selectors like
::-webkit-scrollbar,::before,:has() @keyframesanimations and multi-property transitions- Media queries with custom logic beyond standard breakpoints
- SVG data URIs with embedded colors needing dark mode overrides
appearance: nonewith custom background-image overrides
<style>
/* Scoped CSS -- uses --vx-* tokens */
.custom-scrollbar {
scrollbar-width: thin;
scrollbar-color: rgb(var(--vx-surface-muted)) transparent;
}
:global(.dark) .custom-scrollbar {
scrollbar-color: rgb(var(--neutral-700)) transparent;
}
</style> Best Practices
Use semantic tokens for dark mode compatibility
To ensure components work in both light and dark mode, reference --vx-* tokens instead of hardcoded colors:
/* Recommended */
color: rgb(var(--vx-fg));
background: rgb(var(--vx-surface-muted));
border-color: rgb(var(--vx-edge));
/* Avoid -- hardcoded colors break dark mode */
color: #18181b;
background: #f4f4f5;
border-color: #e4e4e7; Prefer semantic Tailwind classes
<!-- Recommended -->
<div class="text-fg bg-surface border-edge">
<!-- Avoid -- fixed Tailwind colors don't adapt to dark mode -->
<div class="text-zinc-900 bg-white border-zinc-200"> Avoid CSS variable fallbacks
Fallbacks with light-mode defaults can mask missing tokens and break dark mode. If a token is missing, add it to the token system:
/* Avoid -- light-mode fallback masks missing tokens */
color: var(--some-color, #18181b);
/* Recommended -- reference the token directly */
color: rgb(var(--vx-fg)); Opacity support
All --vx-* tokens store space-separated RGB values, enabling opacity modifiers:
/* In Tailwind */
class="bg-primary/10"
/* In scoped CSS */
background: rgb(var(--vx-primary-rgb) / 0.1); Examples
Before (old token names)
.panel {
color: rgb(var(--fg-rgb));
background: rgb(var(--bg-muted-rgb));
border: 1px solid rgb(var(--border-rgb));
} After (new --vx-* tokens)
.panel {
color: rgb(var(--vx-fg));
background: rgb(var(--vx-surface-muted));
border: 1px solid rgb(var(--vx-edge));
} Prefer Tailwind where possible
<!-- Even better -- use Tailwind classes instead of scoped CSS -->
<div class="text-fg bg-surface-muted border border-edge">