X Enterprises

nuxt-x-marketing

Nuxt layer with 68 marketing components (57 active + 11 archived) — hero, features, pricing, testimonials, blog, directory, affiliate, cookie/GDPR, app shell, and a full CSS design system. Zero required props on most components.

nuxt-x-marketing

Marketing website layer for Nuxt 4. Provides 68 components across XMark, X, and XX prefixes (57 actively-recommended + 11 archived legacy components that ship in the published tarball but are not auto-imported) with zero required props on most, dark mode support, responsive design, WCAG 2.0 AA accessibility, and a complete CSS design system (typography, animations, glass effects). Built on Nuxt UI v4.

Installation

npm install @xenterprises/nuxt-x-marketing

Peer dependencies (all required): nuxt ^4.0.0, vue ^3.0.0, @nuxt/ui ^4.6.1, @nuxt/content ^3.0.0, better-sqlite3 ^11.0.0, @iconify-json/lucide ^1.2.82, @tailwindcss/typography ^0.5.0.

npm install @nuxt/ui @nuxt/content better-sqlite3 @iconify-json/lucide @tailwindcss/typography

What the consumer writes

The layer is batteries-included: it ships default pages (/, /blog, /blog/[...slug]), a config-driven default app shell (app.vue rendering XHeaderNav from xMarketing.header, XFooter from xMarketing.footer, and the XMarkPrivacyCookieConsent banner), a blog content collection, and the full CSS design system. A minimal consumer writes four things:

1. nuxt.config.ts — extend the layer:

// nuxt.config.ts
export default defineNuxtConfig({
  extends: "@xenterprises/nuxt-x-marketing",
});

2. app/app.config.ts — site overrides under the xMarketing namespace. It must live in app/, not the project root — at the root, Nuxt 4 silently yields only the Nuxt UI defaults. Everything deep-merges with the layer defaults, so set only what you override:

// app/app.config.ts
export default defineAppConfig({
  xMarketing: {
    name: "Acme Inc",
    url: "https://acme.com",
    header: {
      logo: { src: "/logo.svg", srcDark: "/logo-dark.svg", alt: "Acme" },
      nav: {
        links: [
          { label: "Pricing", to: "/#pricing" },
          { label: "Blog", to: "/blog" },
        ],
        buttons: [{ label: "Get Started", to: "/signup", color: "primary" }],
      },
    },
    footer: {
      logo: { src: "/logo.svg", alt: "Acme" },
      body: "Building the future of modern software.",
      socials: [
        { name: "GitHub", url: "https://github.com/acme", icon: "i-lucide-github" },
      ],
    },
    blog: { active: true, title: "Blog" },
    tracking: { gtmId: "GTM-XXXXXXX" }, // optional; fires only after consent
  },
});

3. content.config.ts — bind the blog collection to your content dir (required; see the gotcha below), and write posts as content/blog/*.md.

4. Environment variables — none. All configuration is via app/app.config.ts.

xMarketing.name and xMarketing.url also drive the shell's SEO wiring: when name is set, the shipped app.vue applies the title template "<page> | <name>" via useSeoMeta and emits og:site_name; the shipped home page reads url for its og:url. Leave both unset to keep bare titles.

To opt out of any default: override app/app.vue to replace the shell entirely, or turn individual shell parts off — xMarketing.header.active: false (navbar), xMarketing.footer.active: false (footer), xMarketing.consent.active: false (cookie-consent banner; tracking scripts then never fire). Override a page by creating your own app/pages/blog/index.vue, or disable the blog entirely with xMarketing.blog.active: false.

Gotcha: the consumer must re-declare the blog collection

Nuxt Content v3 resolves a collection's source against the content/ dir of the layer whose content.config.ts defines it. The layer ships a default blog collection, but its source resolves against the package — so it can never see your content/blog/*.md. Redefine the collection in your own content.config.ts (the consumer's definition wins over the layer's) to bind it to your content dir. This is exactly what the layer's own playground does:

// content.config.ts (consumer project root — same as .playground/content.config.ts)
import { defineContentConfig, defineCollection } from '@nuxt/content'
import { z } from 'zod'

export default defineContentConfig({
  collections: {
    blog: defineCollection({
      type: 'page',
      source: 'blog/**/*.md',
      schema: z.object({
        title: z.string(),
        description: z.string().optional(),
        date: z.date().optional(),
        author: z.union([
          z.string(),
          z.object({
            name: z.string(),
            avatar: z.string().optional(),
            title: z.string().optional(),
            bio: z.string().optional(),
          }),
        ]).optional(),
        image: z.string().optional(),
        category: z.string().optional(),
        tags: z.array(z.string()).optional(),
        published: z.boolean().default(true),
        readingTime: z.number().optional(),
      }),
    }),
  },
})
Breaking (2026-07): the blog moved from Builder.io to Nuxt Content. NUXT_PUBLIC_BUILDERIO_KEY and NUXT_PUBLIC_API_URL are no longer read; migrate posts to content/blog/*.md and install the @nuxt/content + better-sqlite3 peers.

Quick Start

<template>
  <div>
    <XMarkLayoutNavbar
      :links="navLinks"
      :logo="{ src: '/logo.svg', srcDark: '/logo-dark.svg', alt: 'Acme' }"
      :buttons="[
        { label: 'Sign In', to: '/login', variant: 'ghost' },
        { label: 'Get Started', to: '/signup', color: 'primary' },
      ]"
    />

    <XMarkHero
      eyebrow="Welcome"
      title="Build something amazing"
      subtitle="The modern platform for teams."
      :buttons="[{ label: 'Get Started', color: 'primary' }, { label: 'Watch Demo', variant: 'outline' }]"
    />

    <XMarkSection bg="subtle" padding="xl">
      <XMarkFeatures :features="features" layout="grid" :columns="3" />
    </XMarkSection>

    <XMarkSection bg="default" padding="xl">
      <XMarkPricingPlans :plans="pricingPlans" :has-billing-toggle="true" />
    </XMarkSection>

    <XMarkLayoutFooter
      :logo="{ src: '/logo.svg', alt: 'Acme' }"
      description="Building the future of modern software."
      :social="socialLinks"
      :columns="footerColumns"
    />
  </div>
</template>

Components

All components are auto-imported with the XMark prefix. Most components work out of the box with zero required props.

Core Layout

ComponentDescription
XMarkLayoutNavbarFixed navigation with transparent-to-solid scroll transition, mobile menu.
XMarkSectionSection wrapper with bg variants (default, subtle, elevated, bold, transparent), padding, container size, and SVG pattern backgrounds.
XMarkLayoutFooterFull footer with brand, link columns, social icons, optional newsletter.
XMarkLayoutFooterLegalMinimal footer with copyright and legal links only.
XMarkLayoutAnnouncementBarDismissible top-of-page announcement bar.

XMarkLayoutNavbar props: links, logo ({ src, srcDark?, alt? }), buttons, transparent (default true), scrollThreshold (default 100).

XMarkSection props: bg (string variant or full object { variant, color, image, imageAlt, imageOverlay, imagePosition, pattern, patternOpacity, parallax, parallaxSpeed }), padding (none/xs/sm/md/lg/xl), container (smxl/full/none).


Hero & Landing

ComponentDescription
XMarkHeroFull-screen hero with image/video background, overlay, text alignment, scroll indicator.

XMarkHero props: img ({ src, alt? }), video ({ src, poster? }), eyebrow, title, subtitle, buttons ([{ label, to?, color?, variant?, icon? }]), align (left/center/right), verticalAlign (center/bottom), overlay (light/heavy/gradient/none), hasScrollIndicator (default true), includeNavPadding (default false).

<XMarkHero
  image-src="/hero.jpg"
  eyebrow="Welcome"
  title="Build something amazing"
  subtitle="The modern platform for teams."
  align="left"
  overlay="gradient"
  :show-scroll-indicator="true"
>
  <template #actions>
    <UButton size="xl" color="white">Get Started</UButton>
  </template>
</XMarkHero>

Content Sections

ComponentDescription
XMarkFeaturesFeature grid/list/alternating with icons or images. Props: features, layout (grid/list/alternating), columns (2/3/4).
XMarkPricingPlansTiered pricing card grid with monthly/yearly billing toggle.
XMarkPricingComparisonSide-by-side feature comparison table across plans.
XMarkNewsletterFormEmail signup form with default/inline/card/compact variants.
XMarkSectionNewsletterFull-width newsletter section with dark/light variants and pattern backgrounds.
XMarkFAQFAQ block with accordion and two-column layouts.

XMarkPricingPlans props: plans, highlighted, hasBillingToggle (default false), yearlyDiscount (default 10), scale, compact (default true), variant, badges, badgesPosition (top/bottom), badgesAlign (left/center/right). Emits: select.

XMarkPricingComparison props: plans, featureGroups, caption, badges, badgesPosition (top/bottom), badgesAlign (left/center/right). Emits: select.


Blog Components

ComponentDescription
XMarkBlogCardBlog post card with image, excerpt, author, date, category.
XMarkBlogListPaginated, filterable grid of XMarkBlogCard.
XMarkBlogDetailFull post view with hero, prose slot, tags, author bio, prev/next nav, TOC sidebar.
XMarkBlogSidebarSticky sidebar with search, categories, tags, recent posts, newsletter CTA.
XMarkBlogAuthorAuthor display in inline/sm/full/card variants.
XMarkBlogNavigationPrevious/next post navigation bar.
XMarkBlogCTANewsletterCompact in-blog newsletter signup widget.

UI Elements

ComponentDescription
XMarkSocialProofBadgeTrust badges with presets (no-credit-card, cancel-anytime, free-trial, secure, support, setup, gdpr, money-back) or custom icon/label.
XMarkCardGlassGlassmorphism card with optional glow border.
XMarkCardPromo9/16 portrait card with full-bleed image, overlay, badge, and CTA.
XMarkDividerGlowGlowing horizontal section divider with 4 intensity levels and configurable color/height.
XMarkPatternBgSVG background patterns. Patterns: dots, grid, diagonal, topography, circuit, waves, plaid, diagonalPlaid, hexagons, triangles, crosses, zigzag, diamonds.
XMarkSectionStitchSVG section divider with 10 shape variants.
XMarkCodeBlockCode block with Shiki syntax highlighting and optional copy button.
XMarkCTACall-to-action block with default/centered/inline/stacked variants.

Modals & Overlays

ComponentDescription
XMarkModalBase modal wrapper with trigger slot, content slot, footer.
XMarkModalVideoVideo lightbox for YouTube, Vimeo, and direct URLs with optional thumbnail trigger.
XMarkModalImageFull-screen image gallery lightbox with keyboard nav and thumbnails.
XMarkModalChatFloating chat-prompt widget with avatar, message, and CTA.
XMarkModalFeatureFull-screen immersive feature showcase with scrollable content blocks.

ComponentDescription
XMarkPrivacyCookieConsentConsent-aware banner + preferences modal — auto-fires GTM / GA4 / Clarity / Meta Pixel / Hotjar / etc. on consent. The drop-in replacement for sites that want consent + tracking injection from one mount.
XMarkPrivacyCookieBannerBottom cookie consent banner with Accept/Reject/Customize actions (low-level; no auto-tracking).
XMarkPrivacyCookieToastCookie consent delivered via Nuxt UI toast.
XMarkPrivacyGDPRModal for granular cookie category preferences with toggles.

Social Proof

ComponentDescription
XMarkSocialProofTestimonialsTestimonial display in featured/grid/carousel layouts with star ratings.
XMarkSocialProofToastFloating activity toast that cycles through social proof notifications.

Directory Listings

For directory / listing / review sites.

ComponentDescription
XMarkDirectoryListingCardSingle listing in card/row/compact layouts.
XMarkDirectoryListingGridPaginated, searchable, filterable grid of listing cards.
XMarkDirectoryListingDetailFull listing detail page with logo, rating, screenshots, features, and action sidebar.
XMarkDirectoryCategoryHeroDark hero section with icon, name, count, description, and integrated search.
XMarkDirectorySubmitCTATwo-column CTA section encouraging users to submit their listing.

Affiliate & Review Components

For affiliate marketing, product review sites, and comparison posts.

ComponentDescription
XMarkAffiliateDisclosureFTC/Amazon affiliate disclosure. Variants: subtle, banner, inline.
XMarkAffiliateProductCardProduct card with rating, price, pros/cons, buy CTA. Layouts: card, row, compact.
XMarkAffiliateProductGridGrid of product cards with auto rank badges (#1/#2/#3).
XMarkAffiliateProductDetailFull product review: image gallery, editorial score, pros/cons, specs, verdict, sticky buy box.
XMarkAffiliateComparisonTableSide-by-side product comparison with best-value highlighting.

XMarkAffiliateProductCard props: product ({ name, image, price, originalPrice, rating, reviewCount, pros, cons, affiliateUrl, affiliateTag, badge }), layout, showPros, showCons, showRating, showPrice, buttonLabel, buttonIcon, disclosure.


Utilities

ComponentDescription
XMarkButtonBackToTopScroll-to-top floating button. Props: threshold (default 400), position (bottom-right/bottom-left/bottom-center), variant (primary/neutral/glass), icon, label, smooth.

App Shell (X-branded)

App-shell components for X Enterprises products. They come in two flavours that are functionally identical:

  • X-prefixed (X/... path) — historical app-shell naming.
  • XX-prefixed (X/X/... path) — canonical X-branded contract; preferred for new X-products.

All components are config-driven via appConfig.xMarketing.{header, footer} unless otherwise noted.

ComponentDescription
XHeaderApp / XXHeaderProps-based header (navLinks, primaryCta, secondaryCta) with optional transparent mode.
XHeaderNav / XXHeaderNavAppConfig-driven nav header — reads logo, nav links, and CTAs from appConfig.xMarketing.header.
XFooter / XXFooterAppConfig-driven footer with logo, body, columns, socials, background image, and optional newsletter signup.
XFooterXLegal / XXLegalMinimal copyright + legal-link bar; defaults to X Enterprises branding, fully overridable for white-label.

Pick one to avoid duplication: the XX variant is the canonical X-branded choice. Use the X variant only if you're already on the X-prefixed app-shell contract. Use XMarkLayoutNavbar / XMarkLayoutFooter for non-branded (white-label) footers/headers.


Archived (Legacy)

These 11 components ship in the published NPM tarball (@xenterprises/nuxt-x-marketing@1.2.3) but are not auto-imported by Nuxt because their source paths begin with _archive/. Each one is a predecessor of (or alternative to) an actively-recommended component listed above. They are documented for visibility and for legacy consumers who already import them explicitly.

To use any archived component: import it explicitly from its full path — for example:

import XMarkHexBg from '@xenterprises/nuxt-x-marketing/app/components/X/Mark/_archive/Pattern/HexBg.vue'
ComponentReplacement (preferred)Source path
XMarkHexBgXMarkPatternBg (pattern="hexagons")X/Mark/_archive/Pattern/HexBg.vue
XMarkCheckBgXMarkPatternBg (pattern="diagonal")X/Mark/_archive/Pattern/CheckBg.vue
XMarkBackgroundXMarkPatternBg (13 patterns, dark-mode auto color)X/Mark/_archive/Pattern/Background.vue
XMarkDotsBgXMarkPatternBg (pattern="dots")X/Mark/_archive/Pattern/DotsBg.vue
XMarkGlowDividerXMarkDividerGlow (more heights, any Tailwind color)X/Mark/_archive/Pattern/GlowDivider.vue
XMarkWaveBgXMarkPatternBg (pattern="waves")X/Mark/_archive/Pattern/WaveBg.vue
XMarkCircuitBgXMarkPatternBg (pattern="circuit")X/Mark/_archive/Pattern/CircuitBg.vue
XMarkPlaidBgXMarkPatternBg (pattern="plaid")X/Mark/_archive/Pattern/PlaidBg.vue
XMarkSectionStitchArchivedXMarkSectionStitch (10 variants, auto-imported)X/Mark/_archive/Pattern/SectionStitch.vue
XNewsletterSectionXMarkSectionNewsletter (provider-agnostic, emits submit)X/_archive/Newsletter/Section.vue
XNewsletterFormXMarkNewsletterForm (4 variants) or XMarkSectionNewsletterX/_archive/Newsletter/Form.vue

See individual component docs (58.hex-bg.md through 68.newsletter-form.md) for full prop tables and the exact replacement rationale for each.

Composables

All composables are SSR-safe and auto-imported.

ComposableDescription
useScrollReveal(options?)Intersection Observer that adds is-visible to [data-reveal], .xFadeUp, .xFadeIn, .xFadeLeft, .xFadeRight, .xScale, .xFadeUp-stagger elements on scroll. Returns { initScrollReveal, cleanup }.
useParallax(options?)Parallax effect for .xParallax[data-parallax-speed] elements via requestAnimationFrame. Returns { initParallax, cleanup }.
useElementParallax(speed?)Individual element parallax via template ref. Returns { elementRef }.
useStaggerReveal(selector, delay?)Adds incremental transition-delay to [data-reveal] children.
useXBlog()Nuxt Content blog helpers over the blog collection. Returns { blogConfig, normalizeBlogPost, getPosts, getPostByPath, getSurround }.
useConsentTracking()Consent state + gated script injection for xMarketing.tracking (GTM/GA4/Clarity/custom scripts). Powers XMarkPrivacyCookieConsent.
// Scroll animations are initialized globally by marketing.client.ts plugin.
// Use directly in components for fine-grained control:
const { elementRef } = useElementParallax(0.3);

Configuration

// app.config.ts
export default defineAppConfig({
  xMarketing: {
    // Drive shell SEO: title template "<page> | <name>", og:site_name,
    // and og:url on the shipped home page. Leave undefined for bare titles.
    name: "X Enterprises",
    url: "https://x-enterprises.com",
    config: {
      markerProjectId: "", // Optional: Marker.io project ID for feedback widget
      emailMarketingNewsletters: {
        organizationId: "", // Optional: email-marketing org ID
      },
    },
    header: {
      logo: { src: "", srcDark: "", alt: "" },
      nav: { links: [], buttons: [] },
    },
    footer: {
      logo: { src: "", alt: "" },
      body: "",
      bg: { color: "", img: { src: "", alt: "" } },
      socials: [],
      columns: [],
    },
    blog: {
      active: true,
      title: "Blog",
      description: "...",
      meta: { title: "Blog", description: "..." },
    },
  },
});

CSS Design System

The layer ships x-marketing.css with utility classes auto-available in all components.

Typography

ClassDescription
xText-displayDisplay heading — clamp(3rem, 8vw, 6rem), weight 700
xText-headlineSection headline — clamp(2rem, 5vw, 3.5rem), weight 600
xText-titleCard/feature title — clamp(1.25rem, 3vw, 1.75rem), weight 600
xText-bodyBody text — 1.125rem, line-height 1.7
xText-smallCaptions/labels — 0.875rem
xText-eyebrowUppercase label — 0.75rem, 0.1em tracking
xText-gradientGradient text using primary color

Scroll Animations

ClassDescription
xFadeUpFade in + slide up 24px on scroll
xFadeInSimple fade in on scroll
xFadeLeft / xFadeRightFade in from left/right 24px
xScaleScale in (0.95 → 1) on scroll
xFadeUp-staggerStagger children with 100ms delay increments

All animations respect prefers-reduced-motion: reduce.

Hover Effects

ClassDescription
xHover-liftLift up 4px + shadow on hover
xHover-growScale to 1.02 on hover
xHover-glowPrimary color glow shadow on hover
xHover-zoomZoom child <img> to 1.08 on hover

Glass & Glow

ClassDescription
xGlassGlassmorphism — 20px blur, white/70 bg, border, shadow
xGlass-subtle / xGlass-heavy8px / 40px blur variants
xGlow-dividerGlowing horizontal divider
xGlow-borderGlowing gradient border

Environment Variables

No environment variables are required — the layer's runtimeConfig.public is empty. All configuration is via app/app.config.ts under the xMarketing namespace, and blog posts are markdown under content/blog/ via Nuxt Content.

Removed (2026-07): NUXT_PUBLIC_API_URL and NUXT_PUBLIC_BUILDERIO_KEY are no longer read — the blog moved from Builder.io to Nuxt Content.

How It Works

  1. Component registration: All components in app/components/X/Mark/ are auto-imported with the XMark prefix (e.g. XMark/CTA/index.vueXMarkCTA, XMark/Button/BackToTop.vueXMarkButtonBackToTop). App-shell components live under app/components/X/ with the X prefix (e.g. XFooter, XHeaderNav). The X Enterprises branded app-shell equivalents live under app/components/X/X/ with the XX prefix.
  2. Design system: app/assets/css/x-marketing.css defines CSS custom properties for typography scale, spacing, colors, shadows, and motion. Uses Tailwind CSS v4 with @theme static for custom color palettes. Dark mode via .dark selector.
  3. Animations: A client-side plugin (marketing.client.ts) auto-initializes useScrollReveal() and useParallax() globally on mount. Components can also call these composables directly for fine-grained control.
  4. Configuration: app.config.ts defines the xMarketing namespace with Nuxt UI theme overrides. Consumer apps deep-merge their own app.config.ts to customize.
  5. Type system: app/types/marketing.d.ts exports interfaces for all data structures (BlogPost, Feature, PricingPlan, Testimonial, AffiliateProduct, etc.).

Testing

The layer ships three distinct test suites (run inside the layer package, e.g. for contributors — consumers don't run them):

ScriptWhat it runs
npm run test:unitVitest unit suite (test/vitest.config.js) — logic-only tests with Nuxt UI stubs. Aliases: test:run, test:coverage, watch via test:unit:watch.
npm run test:e2eSmoke gatetest/playwright.smoke.config.js, single Chromium project running test/e2e/smoke.spec.js. The Playwright webServer builds and previews .playground on port 3114 and covers the happy paths: homepage hero/navbar/footer render, the pricing monthly→yearly toggle (interactive), the /blog list render, and a /blog/<slug> post render from Nuxt Content.
npm run test:e2e:fullFull multi-browser suitetest/playwright.config.js against nuxi dev on port 3000: accessibility, components, dark-mode, hero, responsive, and visual-regression specs across chromium / firefox / webkit / mobile / tablet projects.
npm run test:visualVisual regression only (same full config, visual-regression project). Snapshots are version-controlled — refresh them deliberately with npm run test:visual:update.

npm test runs test:unit && test:e2e (unit + smoke gate). test:e2e:ui / test:e2e:headed open the smoke suite in Playwright UI / headed mode.

Layer Architecture

PathPurpose
nuxt.config.tsRegisters @nuxt/ui, loads CSS, enables SSR and devtools
app/app.config.tsDefault xMarketing config + Nuxt UI theme overrides + TypeScript augmentation
app/app.vueDefault config-driven shell (XHeaderNav from xMarketing.header, XFooter from xMarketing.footer, cookie-consent banner; also wires the name/url SEO defaults)
app/assets/css/x-marketing.cssFull design system: colors, typography, animations, glass effects
app/components/X/Mark/Generic XMark* marketing components
app/components/X/App-shell X-prefixed components (header, footer, legal)
app/components/X/X/X-branded XX-prefixed components (contract-equivalent to X/*)
app/composables/useScrollReveal, useParallax, useElementParallax, useStaggerReveal, useXBlog, useConsentTracking
content.config.tsDefault blog collection (Nuxt Content v3) — consumers must re-declare it to bind it to their own content/ dir (see the gotcha above)
app/plugins/marketing.client.tsClient plugin: auto-initializes scroll/parallax globally
app/types/marketing.d.tsTypeScript interfaces for all data structures (ImageProp, VideoProp, ButtonProp, LogoProp, Author, BlogPost, Feature, PricingPlan, Testimonial, NavLink, FooterColumn, SocialLink, ComponentSize, SectionBackground, SectionPadding)
app/pages/Default pages: index.vue, blog/index.vue, blog/[...slug].vue

Consumer apps can override app.vue to replace the default shell, or override any page by creating their own pages/blog/index.vue.


AI Context

package: "@xenterprises/nuxt-x-marketing"
type: nuxt-layer
prefixes: [XMark, X, XX]
components: 68
active: 57
archived: 11
use-when: >
  Building a marketing website with Nuxt 4. Provides 57 actively-recommended
  components across `XMark*` (hero, features, pricing, testimonials, blog,
  directory, affiliate, cookie/GDPR, modals), `X*` (app-shell
  header/footer/legal), and `XX*` (X-branded contract-equivalent app shell),
  plus 11 archived legacy components that ship in the published tarball but
  are not auto-imported (their source paths begin with `_archive/`).
  Zero required props on most, dark mode, WCAG 2.0 AA accessibility, and a
  full CSS design system. Includes 6 composables (useScrollReveal, useParallax,
  useElementParallax, useStaggerReveal, useXBlog, useConsentTracking) and
  default pages (index, /blog, /blog/[...slug]). Configure via app.config.ts
  under xMarketing.
Copyright © 2026