@xenterprises/nuxt-x-schema
v0.2.2
Published
Nuxt layer providing Schema.org structured data components for SEO
Readme
@xenterprises/nuxt-x-schema
Nuxt layer providing 16 Schema.org structured data components for SEO. Renders JSON-LD via useHead for full SSR support — search engines see your schema markup on first paint.
Install
npm install @xenterprises/nuxt-x-schemaAdd to your nuxt.config.ts:
export default defineNuxtConfig({
extends: ["@xenterprises/nuxt-x-schema"],
});Usage
<template>
<main>
<h1>{{ article.title }}</h1>
<XSchemaArticle
:headline="article.title"
:description="article.description"
:date-published="article.publishedAt"
:author="article.author"
/>
</main>
</template>Components render no visible HTML. They inject <script type="application/ld+json"> into <head> via Nuxt's useHead, ensuring schema is present in server-rendered HTML.
Configuration
Configure defaults in app.config.ts:
export default defineAppConfig({
xSchema: {
siteUrl: "https://mysite.com",
siteName: "My Site",
siteLogo: "/logo.png",
organizationName: "My Company",
},
});| Option | Type | Default | Required | Description |
|--------|------|---------|----------|-------------|
| siteUrl | string | "https://example.com" | Yes | Base URL for absolute URL construction |
| siteName | string | "My Website" | Yes | Default organization/publisher name |
| siteLogo | string | "/logo.png" | No | Logo URL (relative to siteUrl or absolute) |
| organizationName | string | "" | No | Organization name (falls back to siteName) |
Components
XSchemaArticle
Blog posts, news articles, and written content.
| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| headline | string | — | Yes | Article title |
| datePublished | string | — | Yes | ISO 8601 publication date |
| author | string \| Person \| Array | — | Yes | Author name(s) or Person object(s) |
| description | string | — | No | Article summary |
| image | string \| string[] | — | No | Article image URL(s) |
| dateModified | string | datePublished | No | Last modification date |
| publisher | Organization | app config | No | Publisher organization |
| articleType | string | "BlogPosting" | No | Article, BlogPosting, NewsArticle, TechArticle |
| url | string | — | No | Canonical article URL |
| wordCount | number | — | No | Word count |
XSchemaBreadcrumb
Navigation breadcrumb trail.
| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| items | BreadcrumbItem[] | — | Yes | Array of { label, to } or { name, item } |
Relative URLs in to/item are resolved to absolute URLs using xSchema.siteUrl.
XSchemaEvent
Events and conferences.
| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| name | string | — | Yes | Event name |
| description | string | — | Yes | Event description |
| startDate | string | — | Yes | ISO 8601 start date/time |
| endDate | string | — | Yes | ISO 8601 end date/time |
| eventAttendanceMode | string | "OnlineEventAttendanceMode" | No | Attendance mode |
| eventStatus | string | "EventScheduled" | No | Event status |
| location | object | — | No | Location object |
| url | string | — | No | Event URL |
| image | string \| string[] | — | No | Event image(s) |
| organizer | Organization | app config | No | Organizer |
| offers | Offer | — | No | Ticket offer |
XSchemaFAQ
FAQ pages with question/answer pairs.
| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| items | FAQ[] | — | Yes | Array of { question, answer } (also accepts label/content or name/text) |
| pageTitle | string | — | No | Page title |
| pageDescription | string | — | No | Page description |
| datePublished | string | — | No | Publication date |
| dateModified | string | — | No | Modification date |
| author | string \| Person | — | No | Page author |
XSchemaHowTo
Step-by-step guides and tutorials.
| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| name | string | — | Yes | Guide title |
| steps | HowToStep[] | — | Yes | Array of { name, text, image?, url? } |
| description | string | — | No | Guide description |
| image | string \| string[] | — | No | Guide image(s) |
| totalTime | string | — | No | ISO 8601 duration (e.g. "PT30M") |
| estimatedCost | MonetaryAmount | — | No | Estimated cost |
| supply | string[] | [] | No | Required supplies |
| tool | string[] | [] | No | Required tools |
XSchemaLocalBusiness
Business locations (restaurants, shops, offices).
| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| name | string | — | Yes | Business name |
| businessType | string | — | Yes | Schema.org type (e.g. "Restaurant", "Store") |
| url | string | — | Yes | Business website URL |
| address | PostalAddress | — | Yes | Business address |
| telephone | string | — | No | Phone number |
| email | string | — | No | Email address |
| image | string | — | No | Business image |
| description | string | — | No | Business description |
| openingHoursSpecification | object[] | — | No | Opening hours |
| aggregateRating | AggregateRating | — | No | Rating summary |
| priceRange | string | — | No | Price range (e.g. "$$") |
| sameAs | string[] | — | No | Social media URLs |
XSchemaOffer
Pricing and purchase offers.
| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| name | string | — | Yes | Offer name |
| price | string \| number | — | Yes | Price value |
| description | string | — | No | Offer description |
| priceCurrency | string | "USD" | No | ISO 4217 currency code |
| availability | string | "InStock" | No | Availability status |
| url | string | — | No | Offer URL |
| seller | Organization | app config | No | Seller organization |
| validFrom | string | — | No | Offer valid from date |
| validThrough | string | — | No | Offer valid through date |
| priceValidUntil | string | — | No | Price valid until date |
| itemCondition | string | "NewCondition" | No | Item condition |
XSchemaOrganization
Company or organization information.
| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| name | string | — | Yes | Organization name |
| url | string | — | Yes | Website URL |
| logo | string | — | Yes | Logo image URL |
| legalName | string | — | No | Legal name |
| description | string | — | No | Description |
| email | string | — | No | Contact email |
| telephone | string | — | No | Phone number |
| address | PostalAddress | — | No | Address |
| sameAs | string[] | [] | No | Social media URLs |
| foundingDate | string | — | No | Founding date |
| founder | string \| Person | — | No | Founder (string auto-converts to Person) |
XSchemaPerson
Author and team profiles.
| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| name | string | — | Yes | Person name |
| jobTitle | string | — | No | Job title |
| description | string | — | No | Bio |
| image | string | — | No | Photo URL |
| url | string | — | No | Personal website |
| email | string | — | No | Email |
| telephone | string | — | No | Phone |
| sameAs | string[] | [] | No | Social profiles |
| worksFor | Organization | — | No | Employer |
| knowsAbout | string[] | [] | No | Expertise topics |
| alumniOf | string \| Organization | — | No | School/university |
XSchemaProduct
Products with offers and reviews.
| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| name | string | — | Yes | Product name |
| description | string | — | Yes | Product description |
| offers | Offer | — | Yes | Pricing offer |
| image | string \| string[] | — | No | Product image(s) |
| brand | string \| Organization | app config name | No | Brand |
| aggregateRating | AggregateRating | — | No | Rating summary |
| review | Review[] | — | No | Individual reviews |
| sku | string | — | No | Product SKU |
| manufacturer | string \| Organization | — | No | Manufacturer |
| category | string | — | No | Product category |
XSchemaQAPage
Q&A pages with community answers.
| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| items | QAItem[] | — | Yes | Array of { question, answer, answerAuthor?, upvoteCount? } |
| pageTitle | string | — | No | Page title |
| pageDescription | string | — | No | Page description |
| datePublished | string | — | No | Publication date |
| dateModified | string | — | No | Modification date |
| author | string \| Person | — | No | Page author |
XSchemaReview
Reviews and aggregate ratings.
| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| itemReviewed | object | — | Yes | The item being reviewed (include @type) |
| reviewRating | Rating | — | Yes | { ratingValue, bestRating? } |
| author | string \| Person | — | Yes | Reviewer |
| reviewBody | string | — | No | Review text |
| datePublished | string | — | No | Review date |
| isAggregate | boolean | false | No | Render as AggregateRating instead |
| ratingCount | number | — | No | Total ratings (aggregate mode) |
| reviewCount | number | — | No | Total reviews (aggregate mode) |
XSchemaService
Service pages.
| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| name | string | — | Yes | Service name |
| description | string | — | Yes | Service description |
| serviceType | string | — | Yes | Service type identifier |
| provider | Organization | app config | No | Service provider |
| areaServed | string \| string[] | — | No | Geographic area served |
| offers | Offer | — | No | Service pricing |
| image | string \| string[] | — | No | Service image(s) |
| url | string | — | No | Service page URL |
| category | string | — | No | Service category |
XSchemaSoftwareApplication
Web and mobile applications.
| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| name | string | — | Yes | App name |
| description | string | — | Yes | App description |
| url | string | — | Yes | App URL |
| applicationCategory | string | — | Yes | Category (e.g. "BusinessApplication") |
| operatingSystem | string \| string[] | — | No | Supported OS(es) |
| offers | Offer | — | No | Pricing |
| aggregateRating | AggregateRating | — | No | Rating summary |
| author | string \| Person | — | No | Developer |
| screenshot | string \| string[] | — | No | Screenshot URL(s) |
| releaseNotes | string | — | No | Latest release notes |
XSchemaVideoObject
Video content.
| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| name | string | — | Yes | Video title |
| description | string | — | Yes | Video description |
| thumbnailUrl | string \| string[] | — | Yes | Thumbnail URL(s) |
| uploadDate | string | — | Yes | ISO 8601 upload date |
| duration | string | — | No | ISO 8601 duration (e.g. "PT10M30S") |
| contentUrl | string | — | No | Direct video file URL |
| embedUrl | string | — | No | Embed URL |
| interactionCount | number | — | No | View count |
| author | string \| Person | — | No | Video creator |
XSchemaWebSite
Site-wide schema (typically in default layout).
| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| name | string | — | Yes | Site name |
| url | string | — | Yes | Site URL |
| description | string | — | No | Site description |
| publisher | Organization | — | No | Publisher |
| enableSearchBox | boolean | false | No | Enable Sitelinks Search Box |
| searchUrl | string | — | No | Search URL template (required if enableSearchBox) |
| queryInput | string | "required name=search_term_string" | No | Search query input spec |
Composable: useSchema
Auto-imported composable providing shared utilities for schema generation.
| Method | Returns | Description |
|--------|---------|-------------|
| siteUrl | ComputedRef<string> | Configured site URL (no trailing slash) |
| siteName | ComputedRef<string> | Configured site name |
| resolveUrl(path) | string \| undefined | Convert relative URL to absolute |
| getDefaultOrganization() | Organization | Default org from app config |
| getDefaultPublisher() | object | Default publisher with ImageObject logo |
| normalizeAuthor(author) | Person \| Person[] \| undefined | Convert string/array to Person schema |
| normalizeImage(image) | string[] \| undefined | Ensure image is array |
| useSchemaHead(fn) | void | Inject JSON-LD into <head> via useHead |
Environment Variables
This layer does not require any environment variables. All configuration is via app.config.ts.
How It Works
- Each
XSchema*component accepts typed props describing the content. - Components call
useSchema().useSchemaHead()which wrapsuseHead()to inject a<script type="application/ld+json">tag into the page<head>. - Because
useHeadis SSR-safe, the JSON-LD is rendered server-side and visible to search engine crawlers on first paint — unlike<ClientOnly>approaches that only render client-side. - Default values for publisher/organizer/seller come from
app.config.tsvia theuseSchema()composable, so you configure once and all components use consistent branding. - String values for
author,founder,brand, andalumniOfare automatically converted to proper Schema.org typed objects (Person, Organization, Brand).
Layer Architecture
app/components/X/Schema/*.vue— 16 renderless components, each generating a specific Schema.org typeapp/composables/useSchema.ts— Shared utilities for URL resolution, default org/publisher, author normalization, anduseHeadinjectionapp/types/schema.ts— TypeScript interfaces for all Schema.org types used by componentsapp.config.ts— Layer defaults with type augmentation forxSchemanamespacenuxt.config.ts— Minimal layer config (components and composables auto-imported by Nuxt)
Validation
Test your schema output with:
