X Enterprises

nuxt-x-blog

Nuxt 4 blog layer powered by Nuxt Content v3 — 9 XBL-prefixed components, a useBlog composable, 2 pre-built pages, and configurable blog settings via app.config.ts.

nuxt-x-blog

Blog layer for Nuxt 4. Powered by Nuxt Content v3 — provides 9 auto-imported XBL-prefixed components, a useBlog composable, and 2 pre-built pages. The consuming app writes Markdown posts in content/blog/; the layer handles all UI, routing, pagination, tag filtering, and related-posts logic.

Installation

npm install @xenterprises/nuxt-x-blog
// nuxt.config.ts
export default defineNuxtConfig({
  extends: [['@xenterprises/nuxt-x-blog', { install: true }]],
})

Override defaults in app.config.ts:

export default defineAppConfig({
  xBlog: {
    title: 'Blog',
    description: 'Latest articles and updates',
    postsPerPage: 9,
    dateFormat: 'MMM d, yyyy',
    showAuthor: true,
    showReadingTime: true,
    showTags: true,
    showTableOfContents: true,
    showShareButtons: true,
  },
})

Content Structure

Create blog posts in content/blog/:

content/
  blog/
    my-first-post.md
    getting-started.md

Post Frontmatter

---
title: My First Post
description: A brief description of the post
date: 2025-01-15
author: Jane Doe
image: /images/blog/cover.jpg
tags:
  - nuxt
  - vue
published: true
---

Your post content here...
FieldTypeRequiredDescription
titlestringYesPost title
descriptionstringNoShort excerpt
datestringYesISO date string (used for sorting)
authorstringNoAuthor display name
imagestringNoCover image URL
tagsstringNoTag list for filtering
publishedbooleanNoSet false to draft (default: true)

What the Layer Provides

Components (auto-imported, XBL prefix):

  • XBLPostCard — Blog post preview card with image, title, date, tags, and reading time
  • XBLPostList — Paginated list of XBLPostCard items
  • XBLPostHeader — Post page header with title, meta, author, and cover image
  • XBLPagination — Page navigation controls
  • XBLSearchInput — Search input for filtering posts by title/description
  • XBLTagList — Tag filter list with counts
  • XBLRecentPosts — Sidebar widget showing the most recent posts
  • XBLTableOfContents — Auto-generated table of contents for post pages
  • XBLShareButtons — Social share buttons (Twitter, Facebook, LinkedIn, Email)

Composable:

  • useBlog() — All blog data access methods backed by queryCollection('blog')

Pages:

  • /blog — Blog listing page with search, tag filtering, and pagination
  • /blog/[...slug] — Individual post page with TOC, share buttons, and related posts

App Config Options

Configure under the xBlog key in app.config.ts:

OptionTypeDefaultDescription
titlestring'Blog'Blog section title
descriptionstring'Latest articles and updates'Blog section description
postsPerPagenumber9Posts per page for pagination
dateFormatstring'MMM d, yyyy'Display date format
showAuthorbooleantrueShow author on post cards and pages
showReadingTimebooleantrueShow estimated reading time
showTagsbooleantrueShow tags on post cards and pages
showTableOfContentsbooleantrueShow TOC on post pages
showShareButtonsbooleantrueShow social share buttons on post pages

useBlog() Composable

const {
  config,          // BlogConfig from app.config.ts
  getPosts,        // (options?) => Promise<{ posts, total, page, totalPages, hasMore }>
  getPostByPath,   // (path) => Promise<BlogPost | null>
  getAllTags,       // () => Promise<{ tag, count }[]>
  getRecentPosts,  // (limit?) => Promise<BlogPost[]>
  getRelatedPosts, // (post, limit?) => Promise<BlogPost[]>
  formatDate,      // (dateStr) => string
  estimateReadingTime, // (text) => number  — minutes
} = useBlog()

getPosts(options?)

OptionTypeDefaultDescription
pagenumber1Page number
tagstringFilter by tag
limitnumberpostsPerPagePosts per page override

Returns: { posts: BlogPost[], total: number, page: number, totalPages: number, hasMore: boolean }

BlogPost Type

interface BlogPost {
  id: string
  path: string
  title: string
  description?: string
  date: string
  author?: string
  image?: string
  tags?: string[]
  published?: boolean
  readingTime?: number
  body?: any
}

Minimal Usage Example

<script setup>
const { getPosts } = useBlog()
const { posts } = await getPosts({ page: 1 })
</script>

<template>
  <XBLPostList :posts="posts" />
</template>

Layer Architecture

PathPurpose
nuxt.config.tsRegisters @nuxt/ui, @nuxt/content, Tailwind CSS
app.config.tsAll configurable options under xBlog namespace
app/composables/useBlog.tsBlog data access via queryCollection('blog')
app/components/X/BL/9 auto-imported XBL-prefixed components
app/pages/blog/Listing page and catch-all post page
app/types/index.tsTypeScript interfaces: BlogPost, BlogAuthor, BlogConfig

Environment Variables

This layer reads no environment variables. All configuration is through app.config.ts.


AI Context

package: "@xenterprises/nuxt-x-blog"
use-when: >
  Adding a complete blog to a Nuxt 4 app backed by Nuxt Content v3.
  Write posts as Markdown in content/blog/ with title, date, and published
  frontmatter. Use useBlog() for data access — getPosts() for paginated
  listings, getPostByPath() for post pages, getAllTags() for tag filters.
  All XBL* components are auto-imported; the pre-built /blog and
  /blog/[...slug] pages work out of the box. Configure display options
  (showAuthor, showReadingTime, postsPerPage, etc.) under xBlog in app.config.ts.
Copyright © 2026