A simple, accessible primitive for vertical and horizontal centering in Nuxt.
Centering content in Nuxt often involves repeating the same CSS Grid or Flexbox boilerplate. This module provides a standardized, accessible way to center content with zero hydration issues.
- 🎯 Zero Hydration Issues - Uses
beforeMountand computed styles - ♿ Accessibility First - WCAG 2.2 AA/AAA compliant, no ARIA manipulation
- 🎨 CSS Grid Powered - Uses
place-items: centerfor perfect centering - 🔄 SSR Ready - Optimized for Nuxt 4 server-side rendering
- 📱 Responsive - Supports logical properties (
min-block-size) - 🎭 Polymorphic - Render as any HTML element via
asprop - 📦 Tiny Bundle - Minimal runtime footprint
- 🧪 100% Tested - Full unit and E2E test coverage
npx nuxi module add @colabottles/center-divAdd to your nuxt.config.ts:
export default defineNuxtConfig({
modules: ['@colabottles/center-div']
})<template>
<!-- Basic centering -->
<CenterDiv min-block-size="100vh">
<button>Perfectly Centered</button>
</CenterDiv>
<!-- Horizontal only -->
<CenterDiv axis="horizontal" min-block-size="50vh">
<p>Centered horizontally</p>
</CenterDiv>
<!-- Vertical only -->
<CenterDiv axis="vertical" min-block-size="50vh">
<p>Centered vertically</p>
</CenterDiv>
<!-- Custom element -->
<CenterDiv as="article" min-block-size="100vh">
<h1>Article Content</h1>
</CenterDiv>
</template><template>
<!-- Full viewport centering -->
<div v-center>
Content centered in viewport
</div>
</template>| Prop | Type | Default | Description |
|---|---|---|---|
axis |
'horizontal' | 'vertical' | 'both' |
'both' |
Centering axis |
as |
keyof HTMLElementTagNameMap |
'section' |
HTML element to render |
minBlockSize |
string |
undefined |
Minimum height (uses logical properties) |
Applies full-viewport centering to any element:
- Sets
display: grid - Sets
place-items: center - Sets
height: 100dvh - Sets
width: 100%
This module follows WCAG 2.2 Level AA/AAA guidelines:
- Centers content visually using CSS Grid
- Preserves DOM order and reading sequence
- Respects writing modes and text direction
- Supports zoom and reflow (up to 400%)
- Uses semantic HTML via
asprop
- Does not trap focus
- Does not add ARIA attributes
- Does not change keyboard navigation
- Does not modify semantics
- Does not reorder DOM elements
- WCAG 1.3.2 - Meaningful Sequence: DOM order preserved
- WCAG 1.4.10 - Reflow: No horizontal scrolling at 400% zoom
- WCAG 2.4.3 - Focus Order: Natural tab order maintained
Technique: Pure CSS Grid with logical properties. No JavaScript DOM manipulation.
# Run all tests
pnpm test # Unit tests (7 tests)
pnpm test:e2e # E2E tests (4 tests)
pnpm test:types # TypeScript checks
pnpm lint # ESLint
# Development
pnpm dev # Start playground
pnpm test:watch # Watch mode for unit tests
pnpm test:e2e:ui # E2E with Playwright UI- ✅ Unit tests with Vitest + Vue Test Utils
- ✅ E2E tests with Playwright
- ✅ Accessibility tests with vitest-axe
- ✅ TypeScript type checking
- ✅ ESLint code quality
The module prevents hydration mismatches by:
- Component - Uses computed styles applied during render
- Directive - Uses
beforeMounthook (before hydration completes) - No DOM manipulation - Only inline styles via Vue's
:stylebinding
src/
├── module.ts # Module registration
└── runtime/
├── components/
│ └── CenterDiv.vue # Main component
├── plugin.ts # v-center directive
└── types.ts # TypeScript definitions# Install dependencies
pnpm install
# Start development
pnpm dev
# Run tests
pnpm test
pnpm test:e2e
# Lint
pnpm lint
# Build for production
pnpm prepackCreated for the Nuxt community with accessibility and developer experience in mind.