Hero blocks
Strong first screens with CTA and proof points.
Explore → njX UI is a CDN-first CSS library for
building landing pages fast: ready-made components,
utilities, fluid typography and motion helpers —
copy a block, paste, ship. No framework to learn,
no build step to configure. This page is the full
live preview.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/njx-ui@1/css/style.min.css">
<button class="btn
btn-primary">Launch</button>
<div class="card glass">...</div>
<html data-theme="ocean">
The idea: a landing page in hours, not days — copy ready component classes, switch the theme with one attribute, and never touch a build toolchain.
Landing pages first — promo sites, product pages, launch pages. Also great for docs, prototypes and internal tools where speed matters more than a design-system committee.
_base.css. Change here — updates everywhere.
Set data-theme on <html> and every component, shadow, and gradient updates instantly. No JS required.
<html data-theme="dark"> /* njx-alpine.js preset — load it before Alpine, that's all the JS */
<script defer src="https://cdn.jsdelivr.net/npm/njx-ui@1/js/njx-alpine.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3/dist/cdn.min.js"></script>
/* Toggle dark / light */
<button x-data="njxTheme" @click="toggle()"
x-text="t === 'dark' ? 'Light' : 'Dark'"></button>
/* Pick any of the 9 themes */
<div x-data="njxTheme">
<button @click="set('purple')">Purple</button>
<button @click="set('cyan')">Cyan</button>
<button @click="set('pink')">Pink</button>
</div>
/* data-theme on <html> + localStorage persistence — handled by the preset */ /* 1. JS helpers (add once to your project) */
function applyTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
}
function toggleDarkLight() {
const t = document.documentElement.dataset.theme;
applyTheme(t === 'light' ? 'dark' : 'light');
}
const saved = localStorage.getItem('theme');
if (saved) applyTheme(saved);
/* 2. Toggle variant HTML */
<button onclick="toggleDarkLight()">...</button>
/* 3. Segmented variant HTML */
<div class="sw-seg">
<button onclick="applyTheme('dark')">Dark</button>
<button onclick="applyTheme('light')">Light</button>
</div>
/* 4. CSS active states (pure CSS, no JS) */
html:not([data-theme="light"]) .dark-btn { background: var(--color-primary); }
html[data-theme="light"] .light-btn { background: var(--color-primary); }/* njx-alpine.js preset — zero helpers to write:
<script defer src="https://cdn.jsdelivr.net/npm/njx-ui@1/js/njx-alpine.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3/dist/cdn.min.js"></script> */
/* 1. Toggle variant */
<button x-data="njxTheme" @click="toggle()">...</button>
/* 2. Segmented variant */
<div class="sw-seg" x-data="njxTheme">
<button @click="set('dark')" :class="{ active: t === 'dark' }">Dark</button>
<button @click="set('light')" :class="{ active: t === 'light' }">Light</button>
</div>
/* 3. Icon / settings row — the same one-liners */
<button x-data="njxTheme" @click="set('purple')">Purple</button>
/* 4. CSS active states (pure CSS, no JS) */
html:not([data-theme="light"]) .dark-btn { background: var(--color-primary); }
html[data-theme="light"] .light-btn { background: var(--color-primary); }<!-- _base.css — main colors via var() -->
<div style="color: var(--color-primary)">Primary</div>
<div style="color: var(--color-accent)">Accent</div>
<div style="color: var(--color-success)">Success</div>
<div style="color: var(--color-error)">Error</div>
<div style="color: var(--color-warning)">Warning</div>
<!-- Page background and text -->
<body style="background: var(--сolor-dark); color: var(--color-light)"><!-- _base.css — shades --color-primary-100 ... --color-primary-900 -->
/* Lightest shade */
background: var(--color-primary-100);
/* Base (= --color-primary) */
color: var(--color-primary-500);
/* Darkest */
background: var(--color-primary-900);
/* Example: button hover darker than base */
.btn-primary:hover {
background: var(--color-primary-600);
}
/* Example: light background with accent shade */
.highlight {
background: var(--color-primary-100);
border: 1px solid var(--color-primary-300);
}<!-- _base.css — neutral palette --color-neutral-50 ... 900 -->
/* Light background over card */
background: var(--color-neutral-50);
/* Mid gray — for icons, placeholders */
color: var(--color-neutral-500);
/* Dark background */
background: var(--color-neutral-900);
/* Practical examples */
border: 1px solid var(--color-neutral-300);
color: var(--color-neutral-600); /* muted text */
background: var(--color-neutral-100); /* table zebra rows */color: var(--color-accent-500); /* base accent */
background: var(--color-accent-100); /* light tint */
border: 1px solid var(--color-accent-300);color: var(--color-success-400); /* base */
background: var(--color-success-100); /* pale green bg */color: var(--color-error-500); /* base */
background: var(--color-error-100); /* pale red bg */
border: 1px solid var(--color-error-300);--radius-none
0px
--radius-sm
6px
--radius-md
12px
--radius-lg
20px
--radius-xl
30px
--radius-2xl
40px
--radius-full
9999px
border-radius: var(--radius-sm); /* 6px — input, badge */
border-radius: var(--radius-md); /* 12px — card, panel */
border-radius: var(--radius-lg); /* 20px — modal, sheet */
border-radius: var(--radius-xl); /* 30px — hero block */
border-radius: var(--radius-full); /* pill / avatar */--shadow-sm
Subtle lift
--shadow-md
Card hover
--shadow-lg
Modal · Dropdown
--shadow-primary
Primary glow
--shadow-accent
Accent glow
--shadow-glow
White halo
box-shadow: var(--shadow-sm); /* subtle lift */
box-shadow: var(--shadow-md); /* card hover */
box-shadow: var(--shadow-lg); /* modal / dropdown */
box-shadow: var(--shadow-primary); /* primary glow */
box-shadow: var(--shadow-glow); /* light glow */transition: all var(--ease-fast); /* 0.15s — micro feedback */
transition: all var(--ease); /* 0.30s — standard hover */
transition: all var(--ease-slow); /* 0.50s — entrance / exit */
/* Example */
.btn { transition: background var(--ease-fast), transform var(--ease-fast); }z-index: var(--z-1); /* sticky headers */
z-index: var(--z-10); /* dropdowns */
z-index: var(--z-50); /* tooltips, popovers */
z-index: var(--z-100); /* topbar / navbar */
z-index: var(--z-modal); /* modals, dialogs *//* No code needed — tokens scale automatically at breakpoints.
Any component using var(--fs-base), var(--space-*), etc.
will respond to viewport size changes without media queries.
Override a token in your component for custom scaling: */
@media (max-width: 768px) {
.hero-title { font-size: var(--fs-f-4xl); }
}<!-- _base.css — spacing scale (4px step) -->
/* Small spacing */
gap: var(--space-2); /* 8px */
padding: var(--space-3); /* 12px */
margin: var(--space-4); /* 16px */
/* Medium spacing */
padding: var(--space-6); /* 24px */
gap: var(--space-8); /* 32px */
/* Large spacing */
padding: var(--space-12); /* 48px */
margin-bottom: var(--space-16); /* 64px */
/* Combination */
padding: var(--space-6) var(--space-4); /* 24px 16px */_grid.css.
Gap utilities (.gap-2, .gap-4…) are in _utils.css.
.row + .col-*<div class="row">
<div class="col-6">50%</div>
<div class="col-6">50%</div>
</div>
<div class="row">
<div class="col-8">Main (66%)</div>
<div class="col-4">Sidebar (33%)</div>
</div>
<div class="row">
<div class="col-4">33%</div>
<div class="col-4">33%</div>
<div class="col-4">33%</div>
</div>.grid-col-1 … .grid-col-6.grid-col-2.grid-col-3.grid-col-4.grid-col-5.grid-col-6<!-- Fixed columns: 1–6 -->
<div class="grid-col-2 gap-4">...</div>
<div class="grid-col-3 gap-4">...</div>
<div class="grid-col-4 gap-4">...</div>
<div class="grid-col-5 gap-4">...</div>
<div class="grid-col-6 gap-4">...</div>
<!-- Responsive: collapses on mobile (< 600px → 1 col)
and on tablet (600–899px: 4/5/6 → 2 cols) -->.grid-auto-*.grid-auto-xs — minmax(100px, 1fr).grid-auto-sm — minmax(160px, 1fr).grid-auto-md — minmax(220px, 1fr).grid-auto-lg — minmax(300px, 1fr)<!-- Auto-fit: fills as many cols as fit, wraps automatically -->
<div class="grid-auto-xs gap-2">…</div> <!-- 100px min -->
<div class="grid-auto-sm gap-3">…</div> <!-- 160px min -->
<div class="grid-auto-md gap-4">…</div> <!-- 220px min -->
<div class="grid-auto-lg gap-4">…</div> <!-- 300px min -->
<div class="grid-auto-xl gap-6">…</div> <!-- 400px min -->.grid-sidebar-l — 260px | 1fr.grid-sidebar-r — 1fr | 260px.grid-thirds — 1fr | 2fr | 1fr<!-- Layout presets -->
<div class="grid-sidebar-l gap-4">
<aside>Sidebar (260px)</aside>
<main>Main content</main>
</div>
<div class="grid-sidebar-r gap-4">
<main>Main content</main>
<aside>Sidebar (260px)</aside>
</div>
<div class="grid-thirds gap-4">
<div>Left (1fr)</div>
<div>Main (2fr)</div>
<div>Right (1fr)</div>
</div>_typography.css. Add .fluid for vw-size.
<h1 class="title-hero">Hero Title</h1>
<h2 class="title-xl">Title XL</h2>
<h3 class="title-lg">Title LG</h3>
<h4 class="title-md">Title MD</h4>
<h5 class="title-sm">Title SM</h5>
<h6 class="title-xs">Title XS</h6>
<!-- .fluid — responsive clamp() size -->
<h1 class="title-hero fluid">Fluid Hero</h1>
<h2 class="title-xl fluid text-accent">Fluid Accent</h2><p class="text-lead">Lead — intro paragraph</p>
<p class="text-body">Body — default reading size</p>
<p class="text-sm">Small text</p>
<p class="text-xs">Extra small</p>
<span class="text-caption">CAPTION LABEL</span>
<span class="text-label">UI Label</span>
<!-- Mix text size + color -->
<p class="text-lead text-muted">Muted lead</p>
<p class="text-sm text-primary">Small primary</p><span class="text-primary">Primary</span>
<span class="text-accent">Accent</span>
<span class="text-success">Success</span>
<span class="text-error">Error</span>
<span class="text-warning">Warning</span>
<span class="text-muted">Muted</span>
<span class="text-white">White</span>
<!-- Combine with any heading or text class -->
<h2 class="title-lg text-primary">Colored heading</h2>
<p class="text-sm text-muted">Small muted paragraph</p>
<span class="text-caption text-accent">ACCENT LABEL</span>.tip--info for general information and neutral
notes.
.tip--success to confirm an action or show
a completed state.
.tip--warning to flag something that requires
attention before proceeding.
.tip--danger for destructive or critical
error messages.
.tip--neutral for side notes or supplementary
context.
<!-- Base + variant modifier -->
<div class="tip tip--info">
<svg class="tip-icon">...</svg>
<div>
<div class="tip-title">Info</div>
<div class="tip-body">Message text here.</div>
</div>
</div>
<!-- Without icon -->
<div class="tip tip--warning">
<div>
<div class="tip-title">Warning</div>
<div class="tip-body">This action cannot be undone.</div>
</div>
</div>
<!-- All variants -->
<div class="tip tip--info">...</div>
<div class="tip tip--success">...</div>
<div class="tip tip--warning">...</div>
<div class="tip tip--danger">...</div>
<div class="tip tip--neutral">...</div>--font-* --font-inter --font-poppins --font-montserrat --font-outfit --font-jakarta --font-dm-sans --font-nunito --font-space --font-manrope --font-figtree --font-sora --font-roboto --font-roboto-mono --font-jetbrains --font-fira-code /* Active roles — change here to restyle entire project */
--font-sans: var(--font-inter); /* body text */
--font-heading: var(--font-poppins); /* headings */
--font-mono: var(--font-roboto-mono); /* code */
/* Usage */
font-family: var(--font-sans);
font-family: var(--font-heading);
font-family: var(--font-mono);
/* Or apply a specific font directly */
font-family: var(--font-space);--fs-xs12pxCaption · Label · Helper
--fs-sm14pxSmall text · Button · Badge
--fs-base16pxBody paragraph — default size
--fs-lg18pxLarge body · Lead text
--fs-xl20pxSubheading
--fs-2xl24pxSection title
--fs-3xl30pxH3 heading
--fs-4xl36pxH2
--fs-5xl48pxH1
--fs-6xl60pxDisplay
--fs-hero96pxHero
font-size: var(--fs-sm); /* 14px */
font-size: var(--fs-base); /* 16px — default */
font-size: var(--fs-2xl); /* 24px */
font-size: var(--fs-5xl); /* 48px */
font-size: var(--fs-hero); /* 96px */clamp(min · vw · max)--fs-f-xs10 → 12pxCaption · Label
--fs-f-sm12 → 14pxSmall helper text
--fs-f-base14 → 16pxBody — fluid default
--fs-f-lg16 → 20pxLarge body
--fs-f-xl18 → 24pxSubheading
--fs-f-2xl20 → 30pxSection title
--fs-f-3xl24 → 36pxH3
--fs-f-4xl28 → 48pxH2
--fs-f-hero60 → 120pxHero
font-size: var(--fs-f-base); /* clamp(14px,1.4vw,16px) */
font-size: var(--fs-f-xl); /* clamp(18px,2vw,24px) */
font-size: var(--fs-f-hero); /* clamp(60px,10vw,120px) */--lh-tight0.9
Display headline tight leading impact
--lh-snug1.2
Compact heading or UI label text stays close together
--lh-normal1.5
Standard body copy reads comfortably at this line height
--lh-relaxed1.8
Long-form articles and documentation with open spacing
line-height: var(--lh-tight); /* 0.9 — hero */
line-height: var(--lh-snug); /* 1.2 — headings */
line-height: var(--lh-normal); /* 1.5 — body */
line-height: var(--lh-relaxed); /* 1.8 — articles */_utils.css
(former _util.css removed). Click a class — it copies to clipboard.
_skeleton.css. Base: .skeleton +
size/shape modifiers. Three animations: shimmer, pulse, wave.<div class="skeleton-group">
<span class="skeleton skeleton-lg skeleton-full"></span>
<span class="skeleton skeleton-md skeleton-3/4"></span>
<span class="skeleton skeleton-md skeleton-full"></span>
<span class="skeleton skeleton-md skeleton-2/3"></span>
<span class="skeleton skeleton-sm skeleton-1/2"></span>
</div><div class="skeleton-user">
<span class="skeleton skeleton-circle" style="width:48px;height:48px"></span>
<div class="skeleton-user-info">
<span class="skeleton skeleton-md skeleton-2/3"></span>
<span class="skeleton skeleton-sm skeleton-1/2"></span>
</div>
</div><div class="skeleton-card">
<span class="skeleton skeleton-card-img"></span>
<div class="skeleton-card-body">
<span class="skeleton skeleton-lg skeleton-3/4"></span>
<span class="skeleton skeleton-md skeleton-full"></span>
<span class="skeleton skeleton-md skeleton-2/3"></span>
<span class="skeleton skeleton-xl skeleton-1/3"></span>
</div>
</div><div class="skeleton-list">
<div class="skeleton-list-item">
<span class="skeleton skeleton-circle" style="width:40px;height:40px"></span>
<div class="skeleton-list-item-info">
<span class="skeleton skeleton-md skeleton-1/2"></span>
<span class="skeleton skeleton-sm skeleton-3/4"></span>
</div>
<span class="skeleton skeleton-sm" style="width:52px"></span>
</div>
<!-- repeat rows -->
</div><div class="skeleton-table">
<div class="skeleton-table-row">
<span class="skeleton skeleton-circle" style="width:32px;height:32px"></span>
<span class="skeleton skeleton-sm skeleton-1/4"></span>
<span class="skeleton skeleton-sm skeleton-2/3"></span>
<span class="skeleton skeleton-sm skeleton-1/3"></span>
<span class="skeleton skeleton-sm skeleton-pill" style="width:60px"></span>
</div>
<!-- repeat rows -->
</div><span class="skeleton skeleton-xl skeleton-pill" style="width:100px"></span>
<span class="skeleton skeleton-xl skeleton-pill" style="width:130px"></span>
<span class="skeleton skeleton-xl skeleton-rounded" style="width:110px"></span>
<span class="skeleton skeleton-circle" style="width:48px;height:48px"></span><!-- .skeleton-soft dims to ~40% opacity (ghost/outline button) -->
<span class="skeleton skeleton-xl skeleton-pill" style="width:110px"></span>
<span class="skeleton skeleton-xl skeleton-pill skeleton-soft" style="width:110px"></span>
<span class="skeleton skeleton-xl skeleton-rounded skeleton-soft" style="width:100px"></span>
<span class="skeleton skeleton-circle skeleton-soft" style="width:40px;height:40px"></span><!-- Add .skeleton-wave wrapper to switch animation -->
<div class="skeleton-wave skeleton-group">
<span class="skeleton skeleton-lg skeleton-full"></span>
<span class="skeleton skeleton-md skeleton-3/4"></span>
<span class="skeleton skeleton-md skeleton-full"></span>
<span class="skeleton skeleton-md skeleton-1/2"></span>
</div><div class="skeleton-form">
<div class="skeleton-form-row-inline">
<div class="skeleton-form-row">
<span class="skeleton skeleton-form-label"></span>
<span class="skeleton skeleton-form-input"></span>
</div>
<div class="skeleton-form-row">
<span class="skeleton skeleton-form-label"></span>
<span class="skeleton skeleton-form-input"></span>
</div>
</div>
<div class="skeleton-form-row">
<span class="skeleton skeleton-form-label"></span>
<span class="skeleton skeleton-form-input"></span>
</div>
<!-- submit / cancel / delete row -->
<div style="display:flex;gap:10px;align-items:center">
<span class="skeleton skeleton-xl skeleton-pill" style="width:110px"></span>
<span class="skeleton skeleton-xl skeleton-pill skeleton-soft" style="width:90px"></span>
<span class="skeleton skeleton-xl skeleton-pill skeleton-soft" style="width:90px;margin-left:auto"></span>
</div>
</div><div class="skeleton-stats">
<div class="skeleton-stat">
<span class="skeleton skeleton-stat-icon"></span>
<span class="skeleton skeleton-stat-value"></span>
<span class="skeleton skeleton-stat-label"></span>
</div>
<!-- repeat per stat -->
</div><div class="skeleton-gallery">
<span class="skeleton skeleton-gallery-item"></span>
<span class="skeleton skeleton-gallery-item"></span>
<span class="skeleton skeleton-gallery-item"></span>
<span class="skeleton skeleton-gallery-item"></span>
<span class="skeleton skeleton-gallery-item"></span>
<span class="skeleton skeleton-gallery-item"></span>
</div><div class="skeleton-detail">
<span class="skeleton skeleton-detail-img"></span>
<div class="skeleton-detail-info">
<span class="skeleton skeleton-lg skeleton-3/4"></span>
<span class="skeleton skeleton-md skeleton-full"></span>
<span class="skeleton skeleton-md skeleton-2/3"></span>
<span class="skeleton skeleton-xl skeleton-1/3"></span>
</div>
</div>_animations.css. Three categories: Loop (always-on), Hover-triggered (CSS :hover), Scroll-triggered (IntersectionObserver via njx.js). Combine with .anim-fast, .anim-slow, .anim-delay-* modifiers.
<!-- Fade-in from any direction (one-shot, play on load) -->
<div class="animate-fade-in">Fade in</div>
<div class="animate-fade-in-up">From below</div>
<div class="animate-fade-in-down">From above</div>
<div class="animate-fade-in-left">From left</div>
<div class="animate-fade-in-right">From right</div>
<div class="animate-fade-out">Fade out</div>
<div class="animate-fade-in-out">Fade in/out loop</div>
<!-- Combine with delay + speed -->
<div class="animate-fade-in-up anim-delay-3 anim-slow">Later, slower</div><!-- Continuous float (loop) -->
<div class="animate-float">Gentle levitation</div>
<div class="animate-float-big">Wide arc float</div>
<div class="animate-float-x">Horizontal sway</div>
<div class="animate-bounce">Bouncing loop</div>
<!-- One-shot entrance animations -->
<div class="animate-bounce-in">Bounce in on load</div>
<div class="animate-scale-in">Scale from 0</div>
<div class="animate-flip">3D flip entrance</div>:hover. No JS needed. <!-- Hover-triggered (play once on hover) -->
<div class="animate-spin-y">3D flip Y</div>
<div class="animate-spin-x">3D flip X</div>
<div class="animate-spin-ccw">Counter-clockwise</div>
<div class="animate-spin-bounce">Spin + bounce</div>
<div class="animate-spin-wobble">Wobble</div>
<div class="animate-spin-180">Half turn</div>
<div class="animate-spin-swing">Pendulum swing</div>
<div class="animate-spin-rock">Rock / teeter</div>
<div class="animate-spin-tilt">Tilt 45°</div>
<div class="animate-spin-yoyo">Spin & return</div>
<!-- Loop (always spinning) -->
<svg class="animate-spin">...</svg>
<div class="animate-spin-slow">...</div>
<div class="animate-spin-fade">...</div>
<div class="animate-rotate">...</div><!-- One-shot: play once per trigger -->
<div class="animate-shake">Error state</div> <!-- horizontal shake -->
<div class="animate-shake-y">Vertical shake</div>
<div class="animate-buzz">Buzz / jitter</div>
<div class="animate-tada">Celebration!</div> <!-- scale + rotate party -->
<div class="animate-rubber">Stretch!</div> <!-- rubberBand squish -->
<!-- Loop: continuous attention getter -->
<div class="animate-wiggle">Wiggling...</div>
<div class="animate-heartbeat">● Live</div>
<!-- JS replay trick -->
el.classList.remove("animate-shake");
void el.offsetWidth; // force reflow
el.classList.add("animate-shake");<!-- Alpine replay: toggle the class off, re-add next tick -->
<div x-data="{ on: false, replay() { this.on = false; this.$nextTick(() => this.on = true) } }">
<div :class="{ 'animate-shake': on }" @click="replay()">Error state</div>
<button class="btn btn-sm" @click="replay()">Shake it</button>
</div>
<!-- Loop animations (wiggle / heartbeat) are plain classes — no JS at all -->
<div class="animate-wiggle">Wiggling...</div><!-- Subtle scale pulse (loop) -->
<div class="animate-pulse">Scale 1→1.05</div>
<div class="animate-scale-big">Scale 1→1.1</div>
<div class="animate-ping">Ping / ring pulse</div>
<div class="animate-scale-out">Scale out + fade</div>
<!-- Border glow pulse -->
<div class="animate-border-pulse"></div>
<!-- Skeleton / loading shimmer -->
<div class="animate-shimmer" style="height:16px;border-radius:4px"></div>
<div class="animate-shimmer" style="height:12px;width:60%;border-radius:4px"></div><h2 class="animate-neon-primary" style="color:var(--color-primary)">Primary</h2>
<h2 class="animate-neon-accent" style="color:var(--color-accent)">Accent</h2>
<h2 class="animate-neon-success" style="color:var(--color-success)">Success</h2>
<h2 class="animate-neon-error" style="color:var(--color-error)">Error</h2>
<h2 class="animate-neon-warning" style="color:var(--color-warning)">Warning</h2><h2 class="animate-rainbow">Rainbow</h2>
<h2 class="animate-rainbow-primary">Primary</h2>
<h2 class="animate-rainbow-accent">Accent</h2>
<h2 class="animate-rainbow-success">Success</h2>
<h2 class="animate-rainbow-error">Error</h2>
<h2 class="animate-rainbow-warning">Warning</h2><h2 class="animate-breathe">Breathe</h2>
<h2 class="animate-breathe-primary" style="color:var(--color-primary)">Primary</h2>
<h2 class="animate-breathe-accent" style="color:var(--color-accent)">Accent</h2>
<h2 class="animate-breathe-success" style="color:var(--color-success)">Success</h2>
<h2 class="animate-breathe-error" style="color:var(--color-error)">Error</h2>
<h2 class="animate-breathe-warning" style="color:var(--color-warning)">Warning</h2><!-- Pulsing glow (box-shadow based) -->
<div class="animate-glow">Primary color glow</div>
<div class="animate-glow-accent">Accent color glow</div>
<!-- Expanding border ring -->
<div class="animate-border-pulse"></div>
<!-- Static neon shadow utilities -->
<div class="shadow-neon">White neon glow</div>
<div class="shadow-neon-primary">Theme color glow</div><!-- Pulsing border ring — semantic colors -->
<div class="animate-border-pulse"></div>
<div class="animate-border-pulse-primary"></div>
<div class="animate-border-pulse-accent"></div>
<div class="animate-border-pulse-success"></div>
<div class="animate-border-pulse-error"></div>
<div class="animate-border-pulse-warning"></div><!-- Speed modifiers -->
<div class="animate-spin anim-fast">Very fast</div>
<div class="animate-spin anim-slow">Slow</div>
<div class="animate-spin anim-slower">Very slow</div>
<!-- Delay modifiers -->
<div class="animate-fade-in-up anim-delay-1">0.1s later</div>
<div class="animate-fade-in-up anim-delay-3">0.3s later</div>
<div class="animate-fade-in-up anim-delay-1s">1s later</div>
<!-- Pause / remove -->
<div class="animate-float anim-paused">Paused</div>
<div class="animate-float anim-none">No animation</div>
<!-- Staggered entrance (great for lists) -->
<div class="animate-fade-in-up anim-delay-1">Item 1</div>
<div class="animate-fade-in-up anim-delay-3">Item 2</div>
<div class="animate-fade-in-up anim-delay-5">Item 3</div>njx.js. <div class="scroll-fade-up">From below</div>
<div class="scroll-fade-down">From above</div>
<div class="scroll-fade-left">From right</div>
<div class="scroll-fade-right">From left</div><div class="scroll-zoom-in">Scales 0.8 → 1</div>
<div class="scroll-zoom-out">Scales 1.2 → 1</div><div class="scroll-flip-up">rotateX from bottom</div>
<div class="scroll-flip-left">rotateY from left</div>
<div class="scroll-flip-right">rotateY from right</div><!-- Slight rotation + fade -->
<div class="scroll-rotate-in">Rotates into view</div>
<!-- Blur to sharp + fade -->
<div class="scroll-blur-in">Unblurs into view</div>
<!-- Springy entrance from below -->
<div class="scroll-bounce-in">Bounces in</div>
<!-- Drops from above with overshoot -->
<div class="scroll-drop-in">Drops in</div><!-- Add .scroll-stagger to parent — children animate one by one -->
<div class="scroll-stagger" style="display:flex;gap:10px">
<div>Card 1</div>
<div>Card 2</div>
<div>Card 3</div>
</div>
<!-- Works with any layout -->
<ul class="scroll-stagger">
<li>Item A</li>
<li>Item B</li>
<li>Item C</li>
</ul>_gradients.css. Ready-made gradients for background
and text.
<!-- _gradients.css — background gradients -->
<div class="gradient-primary">...</div>
<div class="gradient-primary-light">...</div>
<div class="gradient-accent">...</div>
<div class="gradient-success">...</div><!-- _gradients.css — combined -->
<div class="gradient-blue-purple">...</div>
<div class="gradient-ocean">...</div>
<div class="gradient-sunset">...</div>
<div class="gradient-nature">...</div>
<div class="gradient-gold">...</div>
<div class="gradient-cosmic">...</div><!-- _gradients.css — dark gradients -->
<div class="gradient-dark-midnight">...</div>
<div class="gradient-dark-void">...</div>
<div class="gradient-dark-blue">...</div>
<div class="gradient-dark-purple">...</div><!-- _gradients.css — gradient text (background-clip: text) -->
<h1 class="text-gradient-primary">Primary</h1>
<h1 class="text-gradient-accent">Accent</h1>
<h1 class="text-gradient-blue-purple">Blue Purple</h1>
<h1 class="text-gradient-sunset">Sunset</h1>
<h1 class="text-gradient-ocean">Ocean</h1>
<h1 class="text-gradient-gold">Gold</h1>
<h1 class="text-gradient-cosmic">Cosmic</h1>
<h1 class="text-gradient-rainbow">Rainbow</h1><!-- _gradients.css — gradient borders (via mask + padding) -->
<div class="border-gradient-primary">...</div>
<div class="border-gradient-accent">...</div>
<div class="border-gradient-rainbow">...</div>
<div class="border-gradient-gold">...</div><!-- _gradients.css — animated gradients (background-size: 200%) -->
<div class="gradient-animated">Bright animated</div>
<div class="gradient-animated-subtle">Soft animated</div><!-- _gradients.css — gradient overlays (::before pseudo) -->
<!-- Element must have position:relative -->
<div class="gradient-overlay-dark" style="position:relative">
<img src="bg.jpg" />
<div style="position:relative;z-index:1">Text above</div>
</div>
<div class="gradient-overlay-primary" style="position:relative">...</div><!-- _gradients.css — conic gradients -->
<div class="gradient-conic">...</div>
<div class="gradient-conic-warm">...</div>
<div class="gradient-conic-cool">...</div>
<div class="gradient-conic-pie">...</div><!-- _gradients.css — mesh (multi-point radial gradients) -->
<div class="gradient-mesh">...</div>
<div class="gradient-mesh-warm">...</div>
<div class="gradient-mesh-cool">...</div><!-- .gradient-shimmer — animated skeleton loader -->
<div class="gradient-shimmer" style="height:20px;border-radius:4px"></div>
<div class="gradient-shimmer" style="height:80px;border-radius:8px"></div><!-- Utility classes with CSS vars --gradient-from / --gradient-to -->
<div class="gradient-horizontal" style="--gradient-from:#f9063f;--gradient-to:#667eea">...</div>
<div class="gradient-vertical" style="--gradient-from:#f9063f;--gradient-to:#667eea">...</div>
<div class="gradient-diagonal" style="--gradient-from:#f9063f;--gradient-to:#667eea">...</div>
<div class="gradient-radial" style="--gradient-from:#f9063f;--gradient-to:transparent">...</div>_backgrounds.css. Muted section backdrops built from
the palette: tints, fades, soft glows and subtle patterns. Apply to
<section> or any wrapper.
<!-- Quiet solid washes with hairline borders — from _backgrounds.css -->
<section class="section bg-tint">…</section> <!-- neutral, dark-secondary 45% -->
<section class="section bg-tint-primary">…</section> <!-- primary 6% -->
<section class="section bg-tint-accent">…</section> <!-- accent 6% -->
<section class="section bg-tint-success">…</section> <!-- success 5% --><!-- Vertical washes that dissolve into the page -->
<section class="section bg-fade-down">…</section> <!-- solid on top → transparent -->
<section class="section bg-fade-up">…</section> <!-- transparent → solid on bottom --><!-- Soft radial color pools (njX hero style, dimmed).
::before covers the block, children stay above it. -->
<section class="section bg-glow">…</section> <!-- primary + accent corners -->
<section class="section bg-glow-primary">…</section> <!-- primary pool from the top -->
<section class="section bg-glow-accent">…</section> <!-- accent pool from the bottom -->
<!-- Wrap several sections to run one glow through all of them -->
<div class="bg-glow">
<section class="section">…</section>
<section class="section">…</section>
</div><!-- Barely-there dot and line grids -->
<section class="section bg-dots">…</section> <!-- 22px dot grid -->
<section class="section bg-grid-lines">…</section> <!-- 40px line grid -->_hovers.css. Hover your mouse over elements.
<!-- _hovers.css: hover-scale-sm | hover-scale | hover-scale-lg | hover-scale-xl -->
<div class="card hover-scale-sm">...</div> <!-- scale(1.02) -->
<div class="card hover-scale">...</div> <!-- scale(1.04) -->
<div class="card hover-scale-lg">...</div> <!-- scale(1.07) -->
<div class="card hover-scale-xl">...</div> <!-- scale(1.12) --><!-- _hovers.css: hover-lift-sm | hover-lift | hover-lift-lg | hover-lift-xl -->
<div class="card hover-lift-sm">...</div> <!-- translateY(-2px) -->
<div class="card hover-lift">...</div> <!-- translateY(-4px) -->
<div class="card hover-lift-lg">...</div> <!-- translateY(-8px) -->
<div class="card hover-lift-xl">...</div> <!-- translateY(-14px) --><!-- hover-glow | hover-glow-accent | hover-glow-success | hover-glow-error | hover-glow-white | hover-glow-intense -->
<div class="card hover-glow">...</div>
<div class="card hover-glow-accent">...</div>
<div class="card hover-glow-success">...</div>
<div class="card hover-glow-error">...</div>
<div class="card hover-glow-white">...</div>
<div class="card hover-glow-intense">...</div><!-- _hovers.css: brightness & filter -->
<div class="card hover-bright">...</div> <!-- brightness(1.15) -->
<div class="card hover-bright-strong">...</div> <!-- brightness(1.3) -->
<div class="card hover-dim">...</div> <!-- brightness(0.8) -->
<div class="card hover-grayscale">...</div> <!-- grayscale(100%) --><!-- _hovers.css: opacity effects -->
<div class="card hover-opacity-sm">...</div> <!-- opacity: 0.85 -->
<div class="card hover-opacity">...</div> <!-- opacity: 0.7 -->
<div class="card hover-opacity-lg">...</div> <!-- opacity: 0.5 -->
<div class="card hover-fade">...</div> <!-- opacity: 0.3 --><!-- _hovers.css: border effects -->
<div class="card hover-border">...</div> <!-- border primary -->
<div class="card hover-border-accent">...</div> <!-- border accent -->
<div class="card hover-border-success">...</div> <!-- border success -->
<div class="card hover-border-glow">...</div> <!-- border + glow --><!-- _hovers.css: rotate effects -->
<div class="card hover-rotate">...</div> <!-- rotate(3deg) -->
<div class="card hover-rotate-neg">...</div> <!-- rotate(-3deg) -->
<div class="card hover-rotate-180">...</div> <!-- rotate(180deg) -->
<div class="card hover-rotate-360">...</div> <!-- rotate(360deg) --><!-- Combo: hover-card (lift+border+shadow), hover-card-glow, hover-mega -->
<div class="card hover-card">...</div>
<div class="card hover-card-glow">...</div>
<div class="card hover-card-slide">...</div>
<div class="card hover-mega">...</div>
<!-- Can be combined -->
<div class="card hover-scale hover-glow">...</div><!-- hover-btn | hover-btn-press | hover-btn-glow | hover-shimmer -->
<button class="btn btn-primary hover-btn">Button</button>
<button class="btn btn-primary hover-btn-press">Press</button>
<button class="btn btn-primary hover-btn-glow">Glow</button>
<!-- hover-shimmer requires overflow:hidden -->
<button class="btn btn-outline hover-shimmer" style="position:relative;overflow:hidden">Shimmer</button><div class="card hover-pulse">...</div>
<!-- hover-shimmer requires position:relative + overflow:hidden -->
<div class="card hover-shimmer" style="position:relative;overflow:hidden">...</div>
<div class="card hover-backdrop-blur">...</div>
<div class="card hover-gradient">...</div><!-- Underline slides left→right -->
<a class="hover-underline-animated" href="#">About</a>
<!-- Underline expands from center -->
<a class="hover-underline-center" href="#">Contact</a>
<!-- Strikethrough line on hover -->
<a class="hover-strikethrough" href="#">Old price</a>
<!-- Text color changes -->
<a class="hover-primary" href="#">Link</a>
<a class="hover-accent" href="#">Link</a><!-- hover-fill — sliding fill from bottom -->
<div class="hover-fill">Fill Primary</div>
<div class="hover-fill hover-fill-accent">Fill Accent</div>
<div class="hover-fill hover-fill-success">Fill Success</div>
<!-- hover-primary-bg — instant color fill -->
<div class="hover-primary-bg">BG Fill</div>
<div class="hover-accent-bg">Accent BG</div>
<div class="hover-success-bg">Success BG</div>
<div class="hover-error-bg">Error BG</div><!-- tilt left -->
<div class="card hover-tilt">...</div>
<!-- tilt right -->
<div class="card hover-tilt hover-tilt-r">...</div><!-- border lines draw top+bottom on hover -->
<a class="hover-border-draw" href="#">Nav link</a>
<div class="card hover-border-draw">...</div>
<button class="btn btn-ghost hover-border-draw">...</button><!-- hover-zoom: overflow:hidden on parent, img scales inside -->
<div class="hover-zoom">
<img src="photo.jpg" alt="">
</div>
<div class="hover-zoom-sm"><img ...></div> <!-- scale(1.05) -->
<div class="hover-zoom-lg"><img ...></div> <!-- scale(1.15) -->
<div class="hover-zoom-out"><img ...></div> <!-- scale(0.95) --><!-- Filter effects (great for images) -->
<img class="hover-grayscale" src="..."> <!-- starts gray, hover reveals color -->
<img class="hover-sepia" src="...">
<img class="hover-invert" src="...">
<img class="hover-bright-strong" src="..."> <!-- brightness(1.3) -->
<img class="hover-dim" src="..."> <!-- brightness(0.85) -->
<img class="hover-blur" src="..."> <!-- blur(2px) on hover -->data-tip attribute — works on any element.
No JS, no wrappers.
<!-- default: top -->
<button data-tip="Tooltip on top">Top</button>
<button data-tip="Tooltip on bottom" data-tip-pos="bottom">Bottom</button>
<button data-tip="Tooltip on left" data-tip-pos="left">Left</button>
<button data-tip="Tooltip on right" data-tip-pos="right">Right</button><!-- no data-tip-color = dark bubble -->
<button data-tip="Default bubble">Default</button>
<button data-tip="Primary" data-tip-color="primary">...</button>
<button data-tip="Success!" data-tip-color="success">...</button>
<button data-tip="Caution" data-tip-color="warning">...</button>
<button data-tip="Danger!" data-tip-color="danger">...</button><!-- on any HTML element -->
<span data-tip="Plain text tooltip">Hover me</span>
<span class="tag tag-primary" data-tip=".tag-primary">tag</span>
<img data-tip="Image tooltip" src="..." />
<div data-tip="var(--color-primary)" data-tip-color="primary"
style="width:40px;height:40px;background:var(--color-primary)">
</div>_buttons.css. Base: .btn + variant.
<button class="btn btn-primary">Primary</button>
<button class="btn btn-accent">Accent</button>
<button class="btn btn-success">Success</button>
<button class="btn btn-error">Error</button>
<button class="btn btn-warning">Warning</button><button class="btn btn-outline">Outline</button>
<button class="btn btn-outline-accent">Accent</button>
<button class="btn btn-outline-success">Success</button>
<button class="btn btn-outline-error">Error</button>
<button class="btn btn-outline-warning">Warning</button>
<button class="btn btn-outline-white">White</button><button class="btn btn-ghost">Ghost</button>
<button class="btn btn-ghost-primary">Primary</button>
<button class="btn btn-ghost-accent">Accent</button>
<button class="btn btn-ghost-success">Success</button>
<button class="btn btn-ghost-error">Error</button>
<button class="btn btn-ghost-warning">Warning</button><!-- Soft: tinted bg + colored text + colored border -->
<!-- Great for secondary actions, tags, status chips -->
<button class="btn btn-soft-primary">Primary</button>
<button class="btn btn-soft-accent">Accent</button>
<button class="btn btn-soft-success">Success</button>
<button class="btn btn-soft-error">Delete</button>
<button class="btn btn-soft-warning">Warning</button>
<button class="btn btn-soft-info">Info</button>
<!-- Combine with sizes -->
<button class="btn btn-soft-primary btn-sm">Small soft</button>
<button class="btn btn-soft-error btn-xs">xs soft</button><a href="#" class="link-btn link-btn-primary">Primary</a>
<a href="#" class="link-btn link-btn-accent">Accent</a>
<a href="#" class="link-btn link-btn-success">Success</a>
<a href="#" class="link-btn link-btn-error">Error</a>
<a href="#" class="link-btn link-btn-warning">Warning</a>
<a href="#" class="link-btn link-btn-dark">Dark</a>
<a href="#" class="link-btn link-btn-light">Light</a><a href="#" class="link-btn link-btn-outline-primary">Primary</a>
<a href="#" class="link-btn link-btn-outline-accent">Accent</a>
<a href="#" class="link-btn link-btn-outline-success">Success</a>
<a href="#" class="link-btn link-btn-outline-error">Error</a>
<a href="#" class="link-btn link-btn-outline-warning">Warning</a>
<a href="#" class="link-btn link-btn-outline-dark">Dark</a>
<a href="#" class="link-btn link-btn-outline-light">Light</a><a href="#" class="link-btn link-btn-ghost-primary">Primary</a>
<a href="#" class="link-btn link-btn-ghost-accent">Accent</a>
<a href="#" class="link-btn link-btn-ghost-success">Success</a>
<a href="#" class="link-btn link-btn-ghost-error">Error</a>
<a href="#" class="link-btn link-btn-ghost-warning">Warning</a>
<a href="#" class="link-btn link-btn-ghost-dark">Dark</a>
<a href="#" class="link-btn link-btn-ghost-light">Light</a><!-- Small -->
<a href="#" class="link-btn link-btn-primary link-btn-sm">Small</a>
<!-- With arrow -->
<a href="#" class="link-btn link-arrow">With arrow</a>
<a href="#" class="link-btn link-btn-primary link-arrow">Filled + arrow</a><button class="btn btn-primary btn-xs">XS</button>
<button class="btn btn-primary btn-sm">SM</button>
<button class="btn btn-primary btn-md">MD (default)</button>
<button class="btn btn-primary btn-lg">LG</button>
<button class="btn btn-primary btn-xl">XL</button><!-- _buttons.css — gradient & glow variants -->
<button class="btn btn-glow-primary">Glow Primary</button>
<button class="btn btn-glow-accent">Glow Accent</button>
<button class="btn btn-glow-success">Glow Success</button>
<button class="btn btn-glow-error">Glow Error</button>
<button class="btn btn-glow-warning">Glow Warning</button>
<button class="btn btn-gradient btn-gradient-primary-accent">Primary Accent</button>
<button class="btn btn-gradient btn-gradient-primary-success">Primary Success</button>
<button class="btn btn-gradient btn-gradient-accent-warning">Accent Warning</button>
<button class="btn btn-gradient btn-gradient-error-warning">Error Warning</button><!-- Gradient border + gradient text, no extra markup -->
<!-- Single colour shimmer -->
<button class="btn btn-outline-gradient btn-outline-gradient-primary">Primary</button>
<button class="btn btn-outline-gradient btn-outline-gradient-accent">Accent</button>
<button class="btn btn-outline-gradient btn-outline-gradient-success">Success</button>
<button class="btn btn-outline-gradient btn-outline-gradient-error">Error</button>
<button class="btn btn-outline-gradient btn-outline-gradient-warning">Warning</button>
<!-- Two-colour shimmer -->
<button class="btn btn-outline-gradient btn-outline-gradient-fire">Fire</button>
<button class="btn btn-outline-gradient btn-outline-gradient-ocean">Ocean</button>
<button class="btn btn-outline-gradient btn-outline-gradient-nature">Nature</button><!-- Animated gradient flow — hover speeds it up -->
<button class="btn btn-gradient-hover btn-gradient-hover-primary">Primary</button>
<button class="btn btn-gradient-hover btn-gradient-hover-accent">Accent</button>
<button class="btn btn-gradient-hover btn-gradient-hover-success">Success</button>
<button class="btn btn-gradient-hover btn-gradient-hover-error">Error</button>
<button class="btn btn-gradient-hover btn-gradient-hover-warning">Warning</button>
<button class="btn btn-gradient-hover btn-gradient-hover-fire">Fire</button>
<button class="btn btn-gradient-hover btn-gradient-hover-ocean">Ocean</button>
<button class="btn btn-gradient-hover btn-gradient-hover-nature">Nature</button><!-- Shifting gradient + light sweep on hover -->
<button class="btn btn-shine btn-shine-primary">Primary</button>
<button class="btn btn-shine btn-shine-accent">Accent</button>
<button class="btn btn-shine btn-shine-success">Success</button>
<button class="btn btn-shine btn-shine-error">Error</button>
<button class="btn btn-shine btn-shine-warning">Warning</button>
<button class="btn btn-shine btn-shine-fire">Fire</button>
<button class="btn btn-shine btn-shine-ocean">Ocean</button>
<button class="btn btn-shine btn-shine-nature">Nature</button><!-- Aura: solid gradient bg + blurred halo ::before that blooms on hover -->
<button class="btn btn-aura btn-aura-sunset">Sunset</button>
<button class="btn btn-aura btn-aura-aurora">Aurora</button>
<button class="btn btn-aura btn-aura-cosmic">Cosmic</button>
<button class="btn btn-aura btn-aura-candy">Candy</button>
<button class="btn btn-aura btn-aura-gold">Gold</button>
<button class="btn btn-aura btn-aura-ice">Ice</button><button class="btn btn-rainbow">Rainbow</button>
<button class="btn btn-rainbow-pastel">Pastel</button>
<button class="btn btn-animated-bg">Animated</button>
<button class="btn btn-animated-fire">Fire</button>
<button class="btn btn-animated-ocean">Ocean</button>
<button class="btn btn-animated-aurora">Aurora</button>
<button class="btn btn-animated-candy">Candy</button><!-- Dark bg button — coloured halo border appears on hover -->
<button class="btn btn-glow-hover">Rainbow</button>
<button class="btn btn-glow-hover btn-glow-hover-fire">Fire</button>
<button class="btn btn-glow-hover btn-glow-hover-ocean">Ocean</button>
<button class="btn btn-glow-hover btn-glow-hover-aurora">Aurora</button>
<button class="btn btn-glow-hover btn-glow-hover-sunset">Sunset</button>
<button class="btn btn-glow-hover btn-glow-hover-gold">Gold</button><!-- btn-icon: square aspect ratio, keeps .btn sizing -->
<button class="btn btn-primary btn-icon btn-xs"><svg ...></svg></button>
<button class="btn btn-primary btn-icon btn-sm"><svg ...></svg></button>
<button class="btn btn-primary btn-icon"><svg ...></svg></button>
<button class="btn btn-accent btn-icon btn-lg"><svg ...></svg></button>
<!-- Square (no pill radius) -->
<button class="btn btn-ghost btn-icon btn-square"><svg ...></svg></button>
<!-- Icon + Text -->
<button class="btn btn-success">
<svg ...></svg>
Download
</button><!-- .btn-group wraps any .btn children -->
<div class="btn-group">
<button class="btn btn-primary btn-sm">Left</button>
<button class="btn btn-primary btn-sm">Center</button>
<button class="btn btn-primary btn-sm">Right</button>
</div>
<!-- Toggle group -->
<div class="btn-group">
<button class="btn btn-outline btn-sm">Day</button>
<button class="btn btn-outline btn-sm">Week</button>
<button class="btn btn-outline btn-sm">Month</button>
</div><!-- .btn-loading — hides text, shows spinner -->
<button class="btn btn-primary btn-loading">Loading</button>
<button class="btn btn-accent btn-loading btn-sm">Loading</button>
<!-- Disabled states -->
<button class="btn btn-primary" disabled>Disabled</button>
<button class="btn btn-error is-disabled">is-disabled</button><!-- Glass: frosted backdrop blur -->
<button class="btn btn-glass">Glass</button>
<!-- Neon: glowing border + text shadow (uses --color-primary) -->
<button class="btn btn-neon">Neon</button>
<button class="btn btn-neon btn-lg">Neon Large</button>
<!-- Glow primary: solid with expanding shadow -->
<button class="btn btn-glow-primary">Glow Primary</button><!-- 3D depth: thick bottom border sinks on :active -->
<button class="btn btn-3d">Primary 3D</button>
<button class="btn btn-3d-success">Success 3D</button>
<button class="btn btn-3d-error">Danger 3D</button>
<button class="btn btn-3d-dark">Dark 3D</button>
<!-- Combine with size modifiers -->
<button class="btn btn-3d btn-lg">Large 3D</button>
<button class="btn btn-3d btn-sm">Small 3D</button><!-- Badge wrap: relative parent + absolute badge -->
<span class="btn-badge-wrap">
<button class="btn btn-primary btn-sm">Inbox</button>
<span class="btn-count">5</span>
</span>
<!-- Dot indicator (no number) -->
<span class="btn-badge-wrap">
<button class="btn btn-ghost btn-icon btn-sm">
<svg .../>
</button>
<span class="btn-dot"></span>
</span>
<!-- Custom badge color -->
<span class="btn-badge-wrap">
<button class="btn btn-dark">Notifications</button>
<span class="btn-count" style="background:#f59e0b">99+</span>
</span>_cards.css.<!-- _cards.css -->
<div class="card">Basic card</div>
<div class="card-glass">Glassmorphism</div>
<div class="card-dark">Dark</div>
<div class="card-bordered">With border</div>
<div class="card-bordered-primary">Primary border</div>
<div class="card-glow">Glow effect</div>
<div class="card-gradient">Gradient</div>card-bg-*card-bg-primary
card-bg-accent
card-bg-success
card-bg-error
card-bg-warning
card-bg-dark
card-bg-light
<div class="card-bg-primary">...</div>
<div class="card-bg-accent">...</div>
<div class="card-bg-success">...</div>
<div class="card-bg-error">...</div>
<div class="card-bg-warning">...</div>
<div class="card-bg-dark">...</div>
<div class="card-bg-light">...</div><div class="card-media">
<!-- image or colored div -->
<img class="card-media-img" src="photo.jpg" alt="">
<div class="card-media-body">
<div class="card-media-label">Category</div>
<div class="card-media-title">Card Title</div>
<div class="card-media-text">Description text goes here.</div>
<a class="btn btn-primary btn-sm">Action</a>
</div>
</div><div class="card-cover">
<!-- background image via inline style or background-image -->
<div class="card-cover-bg" style="background-image:url(photo.jpg)"></div>
<div class="card-cover-body">
<div class="card-cover-label">Category</div>
<div class="card-cover-title">Title</div>
<div class="card-cover-text">Text</div>
</div>
</div><div class="card-gradient-purple">Purple gradient</div>
<div class="card-gradient-sunset">Sunset</div>
<div class="card-gradient-ocean">Ocean</div>
<div class="card-gradient-emerald">Emerald</div>
<div class="card-gradient-fire">Fire</div><div class="card-shadow-sm">Subtle</div>
<div class="card-shadow-md">Medium</div>
<div class="card-shadow-lg">Large</div>
<div class="card-shadow-primary">Primary glow</div>
<div class="card-shadow-accent">Accent glow</div><div class="card-horizontal">
<div class="card-h-img">🚀</div>
<div class="card-h-body">
<div class="card-h-title">Title</div>
<div class="card-h-text">Description text here.</div>
</div>
</div><div class="card-stat">
<div class="card-stat-icon">📦</div>
<div class="card-stat-value">12,480</div>
<div class="card-stat-label">Total orders</div>
<div class="card-stat-trend up">▲ 14.2% this week</div>
</div>
<!-- trend classes: .up (green) / .down (red) -->card-gradient-hover-*card-gradient-hover-primary
card-gradient-hover-accent
card-gradient-hover-success
card-gradient-hover-fire
card-gradient-hover-ocean
card-gradient-hover-sunset
card-gradient-hover-aurora
card-gradient-hover-error
<!-- Gradient appears smoothly on hover -->
<div class="card-gradient-hover card-gradient-hover-primary">...</div>
<div class="card-gradient-hover card-gradient-hover-accent">...</div>
<div class="card-gradient-hover card-gradient-hover-fire">...</div>
<div class="card-gradient-hover card-gradient-hover-ocean">...</div>
<div class="card-gradient-hover card-gradient-hover-sunset">...</div>
<div class="card-gradient-hover card-gradient-hover-aurora">...</div>card-shine-*card-shine-primary
card-shine-accent
card-shine-fire
card-shine-ocean
card-shine-sunset
card-shine-aurora
card-shine-cosmic
<!-- Gradient background + shine sweep on hover -->
<div class="card-shine card-shine-primary">...</div>
<div class="card-shine card-shine-fire">...</div>
<div class="card-shine card-shine-ocean">...</div>
<div class="card-shine card-shine-sunset">...</div>
<div class="card-shine card-shine-aurora">...</div>
<div class="card-shine card-shine-cosmic">...</div>card-outline-gradient-*card-outline-gradient-primary
card-outline-gradient-accent
card-outline-gradient-fire
card-outline-gradient-ocean
card-outline-gradient-sunset
card-outline-gradient-aurora
card-outline-gradient-cosmic
<!-- Animated gradient border, transparent background -->
<div class="card-outline-gradient card-outline-gradient-primary">...</div>
<div class="card-outline-gradient card-outline-gradient-fire">...</div>
<div class="card-outline-gradient card-outline-gradient-ocean">...</div>
<div class="card-outline-gradient card-outline-gradient-sunset">...</div>
<div class="card-outline-gradient card-outline-gradient-aurora">...</div>
<div class="card-outline-gradient card-outline-gradient-cosmic">...</div>card-aura-*card-aura-primary
card-aura-sunset
card-aura-aurora
card-aura-cosmic
card-aura-gold
card-aura-ocean
<!-- Hover triggers glowing aura behind the card -->
<div class="card-aura card-aura-primary">...</div>
<div class="card-aura card-aura-sunset">...</div>
<div class="card-aura card-aura-aurora">...</div>
<div class="card-aura card-aura-cosmic">...</div>
<div class="card-aura card-aura-gold">...</div>
<div class="card-aura card-aura-ocean">...</div>Card content. Description text.
<div class="card-bulma">
<div class="card-header">
<div class="card-header-title">Title</div>
</div>
<div class="card-content">
<p>Card content</p>
</div>
<div class="card-footer">
<a class="card-footer-item">Save</a>
<a class="card-footer-item text-error">Delete</a>
</div>
</div>_tags.css. Tags, badges, dots.<!-- _tags.css — outline tags -->
<span class="tag">default</span>
<span class="tag tag-primary">primary</span>
<span class="tag tag-accent">accent</span>
<span class="tag tag-success">success</span>
<span class="tag tag-error">error</span>
<span class="tag tag-warning">warning</span>
<span class="tag tag-white">white</span><!-- _tags.css — outline variants -->
<span class="tag">default</span>
<span class="tag tag-primary">primary</span>
<span class="tag tag-accent">accent</span>
<span class="tag tag-success">success</span>
<span class="tag tag-error">error</span>
<span class="tag tag-warning">warning</span>
<!-- filled variants -->
<span class="tag tag-filled-primary">filled-primary</span>
<span class="tag tag-filled-success">filled-success</span>
<span class="tag tag-filled-dark">filled-dark</span><!-- Badges -->
<span class="badge">5</span>
<span class="badge badge-primary">99</span>
<span class="badge badge-success">OK</span>
<span class="badge badge-error">!</span>
<span class="badge badge-warning">3</span>
<!-- Dots (status indicators) -->
<span class="dot"></span>
<span class="dot dot-primary"></span>
<span class="dot dot-success"></span>
<span class="dot dot-error"></span>
<span class="dot dot-online"></span>
<span class="dot dot-offline"></span>.inp, .field, .inp-success,
.inp-error, .float-field, .inp-wrap. All via CSS variables.
<!-- _form.css — sizes -->
<input class="inp inp-sm" type="text" placeholder="Small">
<input class="inp" type="text" placeholder="Default">
<input class="inp inp-lg" type="text" placeholder="Large"><!-- inp-primary | inp-success | inp-error | disabled -->
<div class="field">
<div class="field-label">Email</div>
<input class="inp inp-success" type="text" value="[email protected]">
<div class="field-success-msg">✓ Value is correct</div>
</div>
<div class="field">
<div class="field-label">Password</div>
<input class="inp inp-error" type="text" value="wrong">
<div class="field-error-msg">✕ Minimum 8 characters</div>
</div>
<input class="inp" type="text" placeholder="Disabled" disabled><!-- .inp-wrap is required for icons -->
<div class="inp-wrap">
<span class="inp-icon-left">🔍</span>
<input class="inp" type="text" placeholder="Search...">
</div>
<!-- icon on the right -->
<div class="inp-wrap">
<span class="inp-icon-left">🔒</span>
<input class="inp inp-suffix" type="password" placeholder="Password">
<span class="inp-icon-right">👁</span>
</div><!-- placeholder=" " is required (space) -->
<div class="float-field">
<input class="inp" type="text" placeholder=" " id="f1">
<label class="float-label" for="f1">Username</label>
</div>
<div class="float-field">
<input class="inp inp-success" type="email" placeholder=" " id="f2" value="[email protected]">
<label class="float-label" for="f2">Email</label>
</div><!-- .inp-glass — glassmorphism variant (for gradient backgrounds) -->
<input class="inp inp-glass" type="text" placeholder="Glass input">
<select class="inp inp-glass inp-select">
<option>Choose option</option>
<option>Aviator</option>
</select>
<textarea class="inp inp-glass inp-area" placeholder="Textarea..."></textarea><!-- Checkboxes: .check + is-success | is-error -->
<label class="check"><input type="checkbox" checked> Primary</label>
<label class="check is-success"><input type="checkbox" checked> Success</label>
<label class="check is-error"><input type="checkbox"> Error</label>
<!-- Toggle: toggle-track + toggle-label are required -->
<label class="toggle">
<input type="checkbox" checked>
<span class="toggle-track"></span>
<span class="toggle-label">Toggle ON</span>
</label><!-- form-card is-primary | is-success | is-error | is-warning -->
<div class="form-card is-primary">
<div class="form-card-title">🔐 Sign In</div>
<div class="field">
<div class="field-label">Email</div>
<div class="inp-wrap">
<span class="inp-icon-left">✉️</span>
<input class="inp inp-primary" type="email" placeholder="[email protected]">
</div>
</div>
<button class="btn btn-primary" style="width:100%">Login</button>
</div><!-- Input Group: flex + overflow:hidden -->
<div style="display:flex;border-radius:12px;overflow:hidden;border:2px solid var(--lib-comp-brd)">
<input type="text" class="inp" placeholder="Search..." style="flex:1;border:none;border-radius:0">
<button class="btn btn-primary" style="border-radius:0">🔍 Find</button>
</div>
<!-- with prefix -->
<div style="display:flex;border-radius:12px;overflow:hidden;border:2px solid var(--lib-comp-brd)">
<span style="padding:0 16px;display:flex;align-items:center;background:var(--color-dark-secondary);color:var(--color-primary);font-weight:700">https://</span>
<input type="url" class="inp" placeholder="yoursite.com" style="flex:1;border:none;border-radius:0">
</div><!-- Checkbox -->
<label class="check">
<input type="checkbox" checked>
<span>💻 Development</span>
</label>
<!-- Radio -->
<label class="check">
<input type="radio" name="plan" checked>
<span>💳 Bank card</span>
</label>
<label class="check">
<input type="radio" name="plan">
<span>🏦 Transfer</span>
</label>
<!-- Toggle -->
<label class="toggle">
<input type="checkbox" checked>
<span class="toggle-track"></span>
<span class="toggle-label">Notifications</span>
</label>_notifications.css.<!-- progress native: is-primary | is-accent | is-success | is-large -->
<progress class="progress is-primary" value="70" max="100"></progress>
<progress class="progress is-success is-large" value="90" max="100"></progress>
<!-- progress-bar custom: with animation -->
<div class="progress-bar">
<div class="progress-bar-fill" style="width:65%"></div>
</div>
<!-- gradient + animation -->
<div class="progress-bar">
<div class="progress-bar-fill is-gradient is-animated" style="width:80%"></div>
</div>_table.css.| Name | Role | Status | |
|---|---|---|---|
| Alex | [email protected] | Admin | Active |
| Maria | [email protected] | User | Pending |
| Ivan | [email protected] | Editor | Banned |
| Olga | [email protected] | User | Active |
<!-- _table.css: is-striped | is-hoverable | is-bordered + table-container -->
<div class="table-container">
<table class="table is-striped is-hoverable">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alex</td>
<td>[email protected]</td>
<td><span class="tag tag-success">Active</span></td>
</tr>
<tr class="is-selected">
<td>Ivan</td>
<td>[email protected]</td>
<td><span class="tag tag-error">Banned</span></td>
</tr>
</tbody>
</table>
</div>_breadcrumb.css.<!-- _breadcrumb.css: has-arrow-separator | has-dot-separator -->
<nav class="breadcrumb">
<li><a href="#">Home</a></li>
<li><a href="#">Category</a></li>
<li class="is-active"><span>Current page</span></li>
</nav>
<nav class="breadcrumb has-arrow-separator">
<li><a href="#">Home</a></li>
<li><a href="#">Section</a></li>
<li class="is-active"><span>Page</span></li>
</nav>
<nav class="breadcrumb has-dot-separator">
<li><a href="#">Home</a></li>
<li><a href="#">Products</a></li>
<li class="is-active"><span>Details</span></li>
</nav>_breadcrumb.css.<!-- pagination: pagination-prev | pagination-item | pagination-item.is-current | pagination-ellipsis | pagination-next -->
<a class="pagination-prev">← Back</a>
<span class="pagination-item">1</span>
<span class="pagination-item is-current">2</span>
<span class="pagination-item">3</span>
<span class="pagination-ellipsis">…</span>
<span class="pagination-item">10</span>
<a class="pagination-next">Forward →</a>_breadcrumb.css. Color variants: is-primary is-success is-warning is-danger.
<div class="panel is-primary">
<div class="panel-heading">Title</div>
<a class="panel-block is-active"><span class="panel-icon">⭐</span> Item</a>
<a class="panel-block"><span class="panel-icon">📁</span> Item 2</a>
</div><div class="panel is-primary">
<div class="panel-heading">Repository</div>
<div class="panel-tabs">
<a class="is-active">All</a>
<a>Public</a>
</div>
<a class="panel-block is-active">item</a>
</div><div class="panel">
<div class="panel-heading">Team members</div>
<div class="panel-search">
<input type="text" placeholder="Search…">
</div>
<a class="panel-block">
Alice <span class="panel-block-badge">Admin</span>
</a>
<div class="panel-footer">...</div>
</div><div class="panel">
<div class="panel-heading">Features</div>
<label class="panel-block">
<input type="checkbox" checked> Dark mode
<span class="panel-block-meta">enabled</span>
</label>
<div class="panel-footer">
<button class="btn btn-sm btn-primary">Save</button>
</div>
</div><a class="panel-block">
<span class="panel-icon">💬</span> Messages
<span class="panel-block-badge">12</span>
</a><a class="panel-block">
<span class="panel-avatar">AJ</span>
Alice Johnson
<span class="panel-block-meta">32 commits</span>
</a>_links.css. Inline links, color variants, animated
underline and block link cards. Link buttons — see
Buttons ↗.
<a href="#" class="link">Default</a>
<a href="#" class="link link-primary">Primary</a>
<a href="#" class="link link-muted">Muted</a>
<a href="#" class="link link-success">Success</a>
<a href="#" class="link link-danger">Danger</a>
<a href="#" class="link link-warning">Warning</a>
<a href="#" class="link link-info">Info</a><a href="#" class="link link-underline">Always underline</a>
<a href="#" class="link link-slide">Slide on hover</a>
<a href="#" class="link link-plain">No underline</a><a href="#" class="link link-arrow">Read more</a>
<a href="#" class="link link-arrow link-primary">View all</a>
<a href="#" class="link link-external">GitHub</a>
<a href="#" class="link link-external link-muted">Docs</a><a href="#" class="link-card">
<div class="link-card-icon">📄</div>
<div class="link-card-body">
<div class="link-card-title">Documentation</div>
<div class="link-card-desc">Full API reference</div>
</div>
<span class="link-card-arrow">→</span>
</a><div class="link-list">
<a href="#" class="is-active">Dashboard</a>
<a href="#">Profile</a>
<a href="#">Settings</a>
</div>btn, tag,
card, typography and layout utilities.
A polished first screen for SaaS, open-source projects and product launches.
npm i njx-ui
<section class="section">
<div class="container grid grid-2 gap-8 items-center">
<div>
<span class="tag tag-primary">Public beta</span>
<h1 class="title-hero fluid mt-4">Build faster with less CSS</h1>
<p class="text-lead text-muted mt-4">A polished first screen for SaaS, open-source projects and product launches.</p>
<div class="flex gap-3 mt-6">
<a class="btn btn-primary btn-lg" href="#">Start free</a>
<a class="btn btn-outline btn-lg" href="#">View GitHub</a>
</div>
</div>
<div class="card-gradient p-6">npm i njx-ui</div>
</div>
</section>A compact docs hero with search, shortcuts and a clear primary path.
<section class="section">
<div class="container grid grid-2 gap-6 items-center">
<div>
<span class="tag tag-accent">Documentation</span>
<h1 class="title-xl mt-4">Components developers can copy today.</h1>
<p class="text-muted mt-3">A compact docs hero with search and shortcuts.</p>
<input class="input mt-5" placeholder="buttons, cards, forms...">
</div>
<div class="grid gap-3">
<a class="card-glass p-4" href="#">Buttons</a>
<a class="card-glass p-4" href="#">Cards</a>
<a class="card-glass p-4" href="#">Forms</a>
</div>
</div>
</section>A full-width cards section with hierarchy, CTA and reusable card styles.
<section class="section">
<div class="container">
<div class="text-center">
<span class="tag tag-primary">Feature grid</span>
<h2 class="title-lg mt-3">Everything a launch page needs.</h2>
<p class="text-muted">A full-width cards section with hierarchy and CTA.</p>
</div>
<div class="grid grid-3 gap-5 mt-8">
<article class="card-aura card-aura-primary p-5">...</article>
<article class="card-aura card-aura-aurora p-5">...</article>
<article class="card-aura card-aura-gold p-5">...</article>
</div>
</div>
</section><section class="section">
<div class="container grid grid-2 gap-6">
<aside class="card-gradient p-6">...</aside>
<div class="grid gap-4">
<article class="card-glass p-4">...</article>
<article class="card-glass p-4">...</article>
<article class="card-glass p-4">...</article>
</div>
</div>
</section>_sections.css. Containers and wrappers for layouts.
<!-- _sections.css: container, container-sm/md/lg/xl, container-fluid -->
<div class="container"> <!-- max-width: 1280px -->
Content
</div>
<div class="container-sm"> <!-- max-width: 640px -->
Content
</div>
<div class="container-fluid"> <!-- 100% width -->
Content
</div><!-- section | section-sm (32px) | section-lg (96px) -->
<section class="section"> <!-- padding: 64px 0 -->
<div class="container">...</div>
</section>
<section class="section section-sm"> <!-- padding: 32px 0 -->
<div class="container">...</div>
</section>
<section class="section section-lg"> <!-- padding: 96px 0 -->
<div class="container">...</div>
</section><!-- .section-banner: full-screen hero (min-height: 100dvh, bg cover) -->
<section class="section-banner" style="background-image: url(hero.jpg)">
<div class="container text-center">
<span class="tag tag-primary">v2.0 is live</span>
<h1 class="title-hero fluid mt-4">Launch your product<br>with one CDN link</h1>
<p class="text-lead text-muted mt-4">A full-height opening screen: background image or gradient, headline, actions.</p>
<div class="flex justify-center gap-3 mt-6">
<a class="btn btn-gradient btn-lg hover-lift" href="#">Get started →</a>
<a class="btn btn-outline btn-lg" href="#">See examples</a>
</div>
</div>
</section>Hero, feature cards, pricing and CTA blocks built from njX UI primitives.
Drop one stylesheet and compose sections.
Works with all 9 built-in color themes.
CSS first blocks for static and Astro pages.
<section class="section">
<div class="container">
<nav class="flex-center-between">
<strong>LaunchKit</strong>
<div class="flex gap-3">
<a class="link" href="#">Features</a>
<a class="link" href="#">Pricing</a>
<a class="btn btn-primary btn-sm" href="#">Start free</a>
</div>
</nav>
<div class="grid grid-2 gap-8 items-center mt-8">
<div>
<span class="tag tag-primary">New release</span>
<h1 class="title-hero fluid mt-4">Ship your next product page before lunch.</h1>
<p class="text-lead text-muted mt-4">Hero, feature cards, pricing and CTA blocks built from njX UI primitives.</p>
<div class="flex gap-3 mt-6">
<a class="btn btn-primary btn-lg" href="#">Get started</a>
<a class="btn btn-outline btn-lg" href="#">View docs</a>
</div>
</div>
<div class="card-gradient p-6">...</div>
</div>
</div>
</section><section class="section">
<div class="container grid grid-2 gap-6">
<aside class="card-dark p-5">
<strong>Orbit CRM</strong>
<a class="link" href="#">Overview</a>
<a class="link" href="#">Pipeline</a>
<a class="link" href="#">Reports</a>
</aside>
<main class="items-wrapper-col gap-5">
<header class="flex-center-between">
<div>
<span class="tag tag-success">Live</span>
<h2 class="title-md">Revenue overview</h2>
</div>
<button class="btn btn-primary btn-sm">Export</button>
</header>
<div class="grid grid-3 gap-4">
<article class="card-bg-primary">...</article>
<article class="card-bg-success">...</article>
<article class="card-bg-warning">...</article>
</div>
</main>
</div>
</section>Pricing, trust notes and a contact form in one ready page composition.
Docs, prototypes and quick pages.
Teams that ship multiple marketing pages.
Fork, customize and build with the library.
<section class="section">
<div class="container">
<div class="text-center">
<span class="tag tag-accent">Simple plans</span>
<h2 class="title-lg mt-3">Start small. Upgrade when needed.</h2>
<p class="text-muted">Pricing, trust notes and a contact form in one ready page composition.</p>
</div>
<div class="grid grid-3 gap-5 mt-8">
<article class="card-bordered p-5">...</article>
<article class="card-glow p-5">...</article>
<article class="card-bordered p-5">...</article>
</div>
<form class="card-glass flex gap-3 mt-6">
<input class="input" placeholder="Email address">
<button class="btn btn-primary">Request demo</button>
</form>
</div>
</section><div class="items-wrapper-col">...</div>
<div class="list-items-row">...</div><ul class="social-list">
<li><a href="#" aria-label="GitHub"><svg ...></svg></a></li>
<li><a href="#" aria-label="Twitter"><svg ...></svg></a></li>
...
</ul><ul class="social-list social-list-glass">...</ul><ul class="social-list social-list-pills">
<li><a href="#"><svg ...></svg> GitHub</a></li>
</ul><ul class="social-list social-list-colored">
<li><a href="#" data-net="github">...</a></li>
<li><a href="#" data-net="twitter">...</a></li>
</ul><ul class="social-list social-list-minimal">...</ul><ul class="social-list social-list-vertical">...</ul><ul class="social-list social-list-outlined">...</ul><section class="section bg" style="background-image: url(...)">...</section><div class="wrapper">...</div>
<img class="agent" src="..."><section class="section">
<div class="container">
<span class="tag tag-success">Trusted by builders</span>
<h2 class="title-lg mt-3">A small CSS toolkit with real demos.</h2>
<div class="grid grid-3 gap-4 mt-6">
<article class="card-glass p-5"><strong>40+</strong><span>CodePen demos</span></article>
<article class="card-glass p-5"><strong>9</strong><span>themes</span></article>
<article class="card-glass p-5"><strong>0</strong><span>dependencies</span></article>
</div>
</div>
</section><section class="section">
<div class="container card-glass p-6">
<span class="tag tag-primary">Community</span>
<h2 class="title-lg mt-3">Follow the project and ship with us.</h2>
<p class="text-muted">Use this block for footer pages, launch pages and docs home screens.</p>
<ul class="social-list social-list-pills mt-6">
<li><a href="#" data-net="github">GitHub</a></li>
<li><a href="#" data-net="twitter">X / Twitter</a></li>
<li><a href="#" data-net="telegram">Telegram</a></li>
</ul>
</div>
</section>One CDN link, nine themes, zero build steps. Copy a block from the docs and ship.
MIT license · no sign-up · 44 KB gzip
<!-- End-of-page CTA: gradient card, pulse label, primary + ghost action -->
<section class="section">
<div class="container card-gradient p-8">
<span class="tag animate-pulse">● Free & open source</span>
<h2 class="title-lg mt-3">Start your landing tonight.</h2>
<p>One CDN link, nine themes, zero build steps. Copy a block from the docs and ship.</p>
<div class="flex gap-3 mt-6">
<a class="btn btn-light btn-lg hover-lift" href="#">Get njX UI →</a>
<a class="btn btn-outline-white btn-lg" href="#">Browse examples</a>
</div>
<p class="text-sm mt-4" style="opacity:.75">MIT license · no sign-up · 44 KB gzip</p>
</div>
</section><!-- CTA with metrics: outline-gradient card + text-gradient numbers -->
<section class="section">
<div class="container card-outline-gradient p-8 text-center">
<h2 class="title-lg">Why wait? The numbers are in.</h2>
<div class="grid-col-3 gap-6 mt-6">
<div>
<div class="text-3xl font-bold text-gradient-primary">44 KB</div>
<div class="text-sm text-muted">gzipped</div>
</div>
<div>
<div class="text-3xl font-bold text-gradient-primary">9</div>
<div class="text-sm text-muted">themes</div>
</div>
<div>
<div class="text-3xl font-bold text-gradient-primary">0</div>
<div class="text-sm text-muted">build steps</div>
</div>
</div>
<a class="btn btn-shine btn-xl mt-6" href="#">Start building →</a>
</div>
</section>One email a month: new blocks, themes and examples. No spam, unsubscribe anytime.
<!-- Newsletter CTA: glass card + inline form -->
<section class="section">
<div class="container card-glass p-6">
<span class="tag tag-accent">✉ Updates</span>
<h2 class="title-md mt-3">New components, straight to your inbox.</h2>
<p class="text-muted">One email a month: new blocks, themes and examples. No spam, unsubscribe anytime.</p>
<form class="flex gap-3 mt-5">
<input class="input" type="email" placeholder="[email protected]">
<button class="btn btn-primary hover-glow">Subscribe</button>
</form>
</div>
</section>A full contact page block with channel cards and a focused support form.
<section class="section">
<div class="container grid grid-2 gap-6">
<div>
<span class="tag tag-primary">Support</span>
<h2 class="title-lg mt-3">Tell us what you are building.</h2>
<p class="text-muted">A full contact page block with channel cards and a focused form.</p>
<div class="grid grid-3 gap-3 mt-5">
<a class="card-glass p-4" href="#">Email</a>
<a class="card-glass p-4" href="#">GitHub</a>
<a class="card-glass p-4" href="#">Telegram</a>
</div>
</div>
<form class="card-glass p-5 grid gap-3">
<input class="input" type="email" placeholder="[email protected]">
<textarea class="input" rows="5" placeholder="Message"></textarea>
<button class="btn btn-primary">Send message</button>
</form>
</div>
</section>Use this block at the bottom of docs and product pages.
<section class="section">
<div class="container card-gradient p-6">
<span class="tag">Need help?</span>
<h2 class="title-md mt-3">Open an issue or send a message.</h2>
<div class="flex gap-3 mt-5">
<a class="btn btn-light" href="#">Email support</a>
<a class="btn btn-outline-white" href="#">GitHub issue</a>
</div>
</div>
</section>_tab.css. Variants: underline (default),
.tab-nav-pills, .tab-nav-boxed, .tab-nav-card. Modifiers:
.is-full, .tab-nav-sm, .tab-nav-lg.
JS: tabSwitch(btn).
<link> tag — no build step required.
_links.css, new collapse
variants, improved tab system.
<div class="tab-wrap">
<div class="tab-nav">
<button class="tab-btn is-active" onclick="tabSwitch(this)">Tab 1</button>
<button class="tab-btn" onclick="tabSwitch(this)">Tab 2</button>
<button class="tab-btn" onclick="tabSwitch(this)">Tab 3</button>
</div>
<div class="tab-content">
<div class="tab-panel is-active">Content 1</div>
<div class="tab-panel">Content 2</div>
<div class="tab-panel">Content 3</div>
</div>
</div>
<script>
function tabSwitch(btn) {
const wrap = btn.closest(".tab-wrap");
wrap.querySelectorAll(".tab-btn").forEach(b => b.classList.remove("is-active"));
wrap.querySelectorAll(".tab-panel").forEach(p => p.classList.remove("is-active"));
btn.classList.add("is-active");
const idx = [...btn.parentElement.children].indexOf(btn);
wrap.querySelectorAll(".tab-panel")[idx].classList.add("is-active");
}
</script><!-- Alpine drives the same .is-active classes — no tabSwitch() needed -->
<div class="tab-wrap" x-data="{ tab: 0 }">
<div class="tab-nav">
<button class="tab-btn" :class="{ 'is-active': tab === 0 }" @click="tab = 0">Tab 1</button>
<button class="tab-btn" :class="{ 'is-active': tab === 1 }" @click="tab = 1">Tab 2</button>
<button class="tab-btn" :class="{ 'is-active': tab === 2 }" @click="tab = 2">Tab 3</button>
</div>
<div class="tab-content">
<div class="tab-panel" :class="{ 'is-active': tab === 0 }">Content 1</div>
<div class="tab-panel" :class="{ 'is-active': tab === 1 }">Content 2</div>
<div class="tab-panel" :class="{ 'is-active': tab === 2 }">Content 3</div>
</div>
</div><div class="tab-nav tab-nav-pills">
<button class="tab-btn is-active" onclick="tabSwitch(this)">Daily</button>
<button class="tab-btn" onclick="tabSwitch(this)">Weekly</button>
<button class="tab-btn" onclick="tabSwitch(this)">Monthly</button>
</div><!-- njx-alpine.js preset: x-data="njxTabs" — select(i) / isActive(i), no tabSwitch() -->
<div class="tab-wrap" x-data="njxTabs">
<div class="tab-nav tab-nav-pills">
<button class="tab-btn" :class="{ 'is-active': isActive(0) }" @click="select(0)">Daily</button>
<button class="tab-btn" :class="{ 'is-active': isActive(1) }" @click="select(1)">Weekly</button>
<button class="tab-btn" :class="{ 'is-active': isActive(2) }" @click="select(2)">Monthly</button>
</div>
<div class="tab-content">
<div class="tab-panel" :class="{ 'is-active': isActive(0) }">Stats for today</div>
<div class="tab-panel" :class="{ 'is-active': isActive(1) }">Stats for this week</div>
<div class="tab-panel" :class="{ 'is-active': isActive(2) }">Stats for this month</div>
</div>
</div><div class="tab-wrap">...</div>
.tab-nav { display: flex; }
function tabSwitch(btn) { ... }
<div class="tab-nav tab-nav-boxed">...</div>
<div class="tab-content tab-content-bordered">...</div><!DOCTYPE html><html data-theme="dark">...
@import "_base.css"; @import "_buttons.css";
document.addEventListener('DOMContentLoaded', init);
<div class="tab-nav tab-nav-card">
<button class="tab-btn is-active" onclick="tabSwitch(this)">index.html</button>
<button class="tab-btn" onclick="tabSwitch(this)">style.css</button>
</div><!-- njx-alpine.js preset: x-data="njxTabs" — same .tab-nav-card classes -->
<div class="tab-wrap" x-data="njxTabs">
<div class="tab-nav tab-nav-card">
<button class="tab-btn" :class="{ 'is-active': isActive(0) }" @click="select(0)">index.html</button>
<button class="tab-btn" :class="{ 'is-active': isActive(1) }" @click="select(1)">style.css</button>
</div>
<div class="tab-content tab-content-bordered">
<div class="tab-panel" :class="{ 'is-active': isActive(0) }">...</div>
<div class="tab-panel" :class="{ 'is-active': isActive(1) }">...</div>
</div>
</div><!-- Full-width tabs with badges -->
<div class="tab-nav is-full">
<button class="tab-btn is-active" onclick="tabSwitch(this)">
Inbox <span class="tab-badge">4</span>
</button>
<button class="tab-btn" onclick="tabSwitch(this)">
Sent <span class="tab-badge">12</span>
</button>
</div><!-- njx-alpine.js preset: x-data="njxTabs" -->
<div class="tab-wrap" x-data="njxTabs">
<div class="tab-nav is-full">
<button class="tab-btn" :class="{ 'is-active': isActive(0) }" @click="select(0)">
Inbox <span class="tab-badge">4</span>
</button>
<button class="tab-btn" :class="{ 'is-active': isActive(1) }" @click="select(1)">
Sent <span class="tab-badge">12</span>
</button>
</div>
<div class="tab-content">
<div class="tab-panel" :class="{ 'is-active': isActive(0) }">4 unread messages.</div>
<div class="tab-panel" :class="{ 'is-active': isActive(1) }">12 sent messages.</div>
</div>
</div><div class="tab-nav tab-nav-sm">...</div>
<div class="tab-nav">...</div>
<div class="tab-nav tab-nav-lg">...</div>_collapse.css. Supports native <details>
and JS class .is-open. Variants: .collapse-plus .collapse-ghost .collapse-primary. Wrappers: .accordion .accordion-flush.
data-theme on the <html> element.<link> tag. No npm, no webpack, no
PostCSS config. Works in any environment.--color-primary and other CSS variables in your own
:root block. All components update automatically.
<details class="collapse">
<summary class="collapse-header">
Title <span class="collapse-icon"></span>
</summary>
<div class="collapse-body">Content goes here.</div>
</details>.is-open to the .collapse element to expand it.
Remove to collapse. Use any event — click, hover, programmatic..is-open to the wrapper div in HTML. No JS
needed at load time.<div class="collapse">
<div class="collapse-header" onclick="collapseToggle(this)">
Title <span class="collapse-icon"></span>
</div>
<div class="collapse-body">Content</div>
</div>
<script>
function collapseToggle(header) {
header.closest('.collapse').classList.toggle('is-open');
}
</script><!-- Same .is-open class — Alpine just toggles it. njx.js not needed. -->
<div class="collapse" x-data="{ open: false }" :class="{ 'is-open': open }">
<div class="collapse-header" @click="open = !open">
Title <span class="collapse-icon"></span>
</div>
<div class="collapse-body">Content</div>
</div>
<!-- Exclusive accordion — one item open at a time -->
<div class="accordion" x-data="{ active: null }">
<div class="collapse" :class="{ 'is-open': active === 1 }">
<div class="collapse-header" @click="active = active === 1 ? null : 1">
Section A <span class="collapse-icon"></span>
</div>
<div class="collapse-body">Content A</div>
</div>
<div class="collapse" :class="{ 'is-open': active === 2 }">
<div class="collapse-header" @click="active = active === 2 ? null : 2">
Section B <span class="collapse-icon"></span>
</div>
<div class="collapse-body">Content B</div>
</div>
</div>.collapse-plus — shows a + that morphs into — when open.
.collapse-ghost — transparent background and border. Great
inside cards or sidebars..collapse-primary — tinted border and header that matches
your theme's primary color.<!-- Plus/minus icon -->
<details class="collapse collapse-plus">...</details>
<!-- Ghost (transparent) -->
<details class="collapse collapse-ghost">...</details>
<!-- Primary accent -->
<details class="collapse collapse-primary">...</details>.accordion wrapper adds 6px gap
between items.<div class="accordion">
<details class="collapse">
<summary class="collapse-header">Section A <span class="collapse-icon"></span></summary>
<div class="collapse-body">Content A</div>
</details>
<details class="collapse">
<summary class="collapse-header">Section B <span class="collapse-icon"></span></summary>
<div class="collapse-body">Content B</div>
</details>
</div>.accordion-flush wrapper removes individual borders and
joins all items into one bordered block with dividers between them.<link> tag — that's it. No npm, no build tools. Works
offline too.color-mix() which requires Chrome
111+, Firefox 113+, Safari 16.2+.:root or any parent element. Scoped
theming is fully supported.<div class="accordion-flush">
<details class="collapse">
<summary class="collapse-header">Item 1 <span class="collapse-icon"></span></summary>
<div class="collapse-body">Content</div>
</details>
<details class="collapse">
<summary class="collapse-header">Item 2 <span class="collapse-icon"></span></summary>
<div class="collapse-body">Content</div>
</details>
</div>_dropdown.css. Native <details> or JS
dropdownToggle(). Positions: .dropdown-right .dropdown-top .dropdown-center. Variants: .dropdown-primary .dropdown-dark.
<details class="dropdown">
<summary class="dropdown-trigger btn btn-ghost btn-sm">
Menu <span class="dropdown-arrow"></span>
</summary>
<div class="dropdown-menu">
<div class="dropdown-label">Section</div>
<a href="#" class="dropdown-item">Item</a>
<a href="#" class="dropdown-item is-active">Active</a>
<div class="dropdown-divider"></div>
<a href="#" class="dropdown-item is-danger">Delete</a>
<a href="#" class="dropdown-item" disabled>Disabled</a>
</div>
</details><details class="dropdown">... <!-- left (default) -->
<details class="dropdown dropdown-center">... <!-- center -->
<details class="dropdown dropdown-right">... <!-- right -->
<details class="dropdown dropdown-top">... <!-- opens upward --><!-- Primary — colored top stripe + themed border -->
<details class="dropdown dropdown-primary">...</details>
<!-- Dark — always dark menu -->
<details class="dropdown dropdown-dark">...</details><div class="dropdown" id="my-dd">
<button class="btn btn-ghost btn-sm"
onclick="dropdownToggle(this.parentElement)">
Menu <span class="dropdown-arrow"></span>
</button>
<div class="dropdown-menu">
<a href="#" class="dropdown-item">Item</a>
</div>
</div>
<script>
function dropdownToggle(el) {
el.classList.toggle("is-open");
}
// Close on outside click
document.addEventListener("click", e => {
document.querySelectorAll(".dropdown.is-open").forEach(dd => {
if (!dd.contains(e.target)) dd.classList.remove("is-open");
});
});
</script><!-- Same .is-open class; @click.outside replaces the document listener -->
<div class="dropdown" x-data="{ open: false }"
:class="{ 'is-open': open }" @click.outside="open = false">
<button class="btn btn-ghost btn-sm" @click="open = !open">
Menu <span class="dropdown-arrow"></span>
</button>
<div class="dropdown-menu">
<a href="#" class="dropdown-item" @click="open = false">Item</a>
</div>
</div>_popups.css. Variant is set on .lib-modal-box — the overlay is automatically colored via :has(). Close
— Escape or click the overlay.
<!-- Overlay is automatically colored via :has() -->
<!-- Variants: is-primary | is-success | is-error | is-warning | is-info -->
<div id="my-modal" class="lib-modal-overlay"
onclick="if(event.target===this)closeModal(this)">
<div class="lib-modal-box is-success">
<button class="lib-modal-close"
onclick="closeModal(document.getElementById('my-modal'))">✕</button>
<div class="lib-modal-icon-wrap">✅</div>
<div class="lib-modal-title">Success!</div>
<div class="lib-modal-text">Description of the action or result.</div>
<div class="lib-modal-actions">
<button class="btn btn-success btn-sm">Great!</button>
<button class="btn btn-ghost btn-sm">Close</button>
</div>
</div>
</div>
<script>
function openModal(id) {
document.getElementById(id).classList.add("open");
document.body.style.overflow = "hidden";
}
function closeModal(el) {
el.classList.remove("open");
document.body.style.overflow = "";
}
// close on Escape
document.addEventListener("keydown", e => {
if (e.key === "Escape")
document.querySelectorAll(".lib-modal-overlay.open")
.forEach(closeModal);
});
</script><!-- One Alpine root drives every variant: open = 'success' | 'error' | … -->
<!-- Single modal? Take the njx-alpine.js preset: x-data="njxModal" (show/hide, Escape, scroll lock) -->
<div x-data="{ open: null }" @keydown.escape.window="open = null">
<button class="btn btn-success btn-sm" @click="open = 'success'">✅ Success</button>
<button class="btn btn-danger btn-sm" @click="open = 'error'">❌ Error</button>
<div class="lib-modal-overlay" :class="{ open: open === 'success' }" @click.self="open = null">
<div class="lib-modal-box is-success">
<button class="lib-modal-close" @click="open = null">✕</button>
<div class="lib-modal-icon-wrap">✅</div>
<div class="lib-modal-title">Success!</div>
<div class="lib-modal-text">Description of the action or result.</div>
<div class="lib-modal-actions">
<button class="btn btn-success btn-sm" @click="open = null">Great!</button>
<button class="btn btn-ghost btn-sm" @click="open = null">Close</button>
</div>
</div>
</div>
<div class="lib-modal-overlay" :class="{ open: open === 'error' }" @click.self="open = null">
<div class="lib-modal-box is-error">...</div>
</div>
</div><!-- Small: max-width 340px -->
<div class="lib-modal-box is-sm">...</div>
<!-- Large: max-width 620px -->
<div class="lib-modal-box is-lg">...</div>
<!-- Combine size + color -->
<div class="lib-modal-box is-sm is-primary">...</div><!-- Add .is-column to stack buttons vertically -->
<div class="lib-modal-actions is-column">
<button class="btn btn-error btn-sm">Delete permanently</button>
<button class="btn btn-warning btn-sm">Archive instead</button>
<button class="btn btn-ghost btn-sm">Cancel</button>
</div><!-- Place any HTML inside .lib-modal-box -->
<div class="lib-modal-box is-primary">
<div class="lib-modal-icon-wrap">📝</div>
<div class="lib-modal-title">Send a message</div>
<div class="lib-modal-text">Fill in the details below.</div>
<!-- form fields -->
<input type="text" placeholder="Your name" />
<textarea placeholder="Your message..."></textarea>
<div class="lib-modal-divider"></div>
<div class="lib-modal-actions">
<button class="btn btn-primary btn-sm">Send</button>
<button class="btn btn-ghost btn-sm">Cancel</button>
</div>
</div><!-- Trigger button -->
<button onclick="openModal('my-modal')">Open</button>
<!-- Modal (place anywhere in body) -->
<div id="my-modal" class="lib-modal-overlay"
onclick="if(event.target===this)closeModal(this)">
<div class="lib-modal-box is-primary">
<button class="lib-modal-close"
onclick="closeModal(document.getElementById('my-modal'))">✕</button>
<div class="lib-modal-icon-wrap">🔷</div>
<div class="lib-modal-title">Title here</div>
<div class="lib-modal-text">Description text.</div>
<div class="lib-modal-divider"></div>
<div class="lib-modal-actions">
<button class="btn btn-primary btn-sm">Confirm</button>
<button class="btn btn-ghost btn-sm">Cancel</button>
</div>
</div>
</div>
<script>
function openModal(id) {
document.getElementById(id).classList.add("open");
document.body.style.overflow = "hidden";
}
function closeModal(el) {
el.classList.remove("open");
document.body.style.overflow = "";
}
document.addEventListener("keydown", e => {
if (e.key === "Escape")
document.querySelectorAll(".lib-modal-overlay.open").forEach(closeModal);
});
</script><!-- Same .open class on the overlay — Alpine replaces openModal/closeModal -->
<div x-data="{ open: false }" @keydown.escape.window="open = false">
<button class="btn btn-primary" @click="open = true">Open</button>
<div class="lib-modal-overlay" :class="{ open }" @click.self="open = false">
<div class="lib-modal-box is-primary">
<button class="lib-modal-close" @click="open = false">✕</button>
<div class="lib-modal-icon-wrap">🔷</div>
<div class="lib-modal-title">Title here</div>
<div class="lib-modal-text">Description text.</div>
<div class="lib-modal-divider"></div>
<div class="lib-modal-actions">
<button class="btn btn-primary btn-sm" @click="open = false">Confirm</button>
<button class="btn btn-ghost btn-sm" @click="open = false">Cancel</button>
</div>
</div>
</div>
</div><!-- ── Color variants — add modifier to .lib-modal-box ── -->
<!-- default | is-primary | is-success | is-error | is-warning | is-info -->
<div id="modal-1" class="lib-modal-overlay" onclick="if(event.target===this)closeModal(this)">
<div class="lib-modal-box is-success">
<button class="lib-modal-close" onclick="closeModal(document.getElementById('modal-1'))">✕</button>
<div class="lib-modal-icon-wrap">✅</div>
<div class="lib-modal-title">Success!</div>
<div class="lib-modal-text">Description of the action or result.</div>
<div class="lib-modal-actions">
<button class="btn btn-success btn-sm">Confirm</button>
<button class="btn btn-ghost btn-sm">Cancel</button>
</div>
</div>
</div>
<!-- ── Size variants ── -->
<div class="lib-modal-box is-sm">...</div> <!-- max-width: 340px -->
<div class="lib-modal-box is-lg">...</div> <!-- max-width: 620px -->
<!-- ── Stacked actions ── -->
<div class="lib-modal-box is-column">
<div class="lib-modal-actions">
<button class="btn btn-primary btn-sm">Option A</button>
<button class="btn btn-ghost btn-sm">Option B</button>
<button class="btn btn-ghost btn-sm">Option C</button>
</div>
</div>
<!-- ── Form inside ── -->
<div class="lib-modal-box">
<div class="lib-modal-title">Edit profile</div>
<form style="display:flex;flex-direction:column;gap:12px;margin-top:16px">
<input class="inp" type="text" placeholder="Name">
<input class="inp" type="email" placeholder="Email">
<div class="lib-modal-actions">
<button class="btn btn-primary btn-sm" type="submit">Save</button>
<button class="btn btn-ghost btn-sm" type="button">Cancel</button>
</div>
</form>
</div>
<script>
function openModal(id) {
document.getElementById(id).classList.add("open");
document.body.style.overflow = "hidden";
}
function closeModal(el) {
el.classList.remove("open");
document.body.style.overflow = "";
}
document.addEventListener("keydown", e => {
if (e.key === "Escape")
document.querySelectorAll(".lib-modal-overlay.open").forEach(closeModal);
});
</script><!-- njx-alpine.js preset: x-data="njxModal" — show()/hide(), Escape,
backdrop click and body scroll lock handled by the preset -->
<div x-data="njxModal">
<div class="card hover-lift" @click="show()">
<div class="lib-modal-title">Default modal</div>
<div class="text-sm text-muted">Click to preview</div>
</div>
<div class="lib-modal-overlay">
<div class="lib-modal-box">
<button class="lib-modal-close" @click="hide()">✕</button>
<div class="lib-modal-icon-wrap">⬜</div>
<div class="lib-modal-title">Default</div>
<div class="lib-modal-text">Neutral styling, no color tint.</div>
<div class="lib-modal-actions">
<button class="btn btn-primary btn-sm" @click="hide()">Confirm</button>
<button class="btn btn-ghost btn-sm" @click="hide()">Cancel</button>
</div>
</div>
</div>
</div>
<!-- Color / size variants — the same .lib-modal-box modifiers -->
<div class="lib-modal-box is-success">...</div>
<div class="lib-modal-box is-sm is-primary">...</div>sidebarOpen(id) / sidebarClose(id) / sidebarToggle(id).
<!-- Trigger -->
<button class="btn btn-primary" onclick="sidebarOpen('my-sidebar')">Open</button>
<!-- Backdrop -->
<div class="sidebar-backdrop" id="my-sidebar-backdrop" onclick="sidebarClose('my-sidebar')"></div>
<!-- Sidebar -->
<aside class="sidebar" id="my-sidebar">
<div class="sidebar-header">
<span class="sidebar-title">Menu</span>
<button class="sidebar-close" onclick="sidebarClose('my-sidebar')">✕</button>
</div>
<div class="sidebar-body">
<nav class="sidebar-nav">
<a class="sidebar-link is-active" href="#">Dashboard</a>
<a class="sidebar-link" href="#">Profile</a>
<a class="sidebar-link" href="#">Settings</a>
</nav>
</div>
</aside><!-- Same .is-open / .is-visible classes — sidebarOpen()/sidebarClose() not needed -->
<div x-data="{ open: false }" @keydown.escape.window="open = false">
<button class="btn btn-primary" @click="open = true">Open</button>
<div class="sidebar-backdrop" :class="{ 'is-visible': open }" @click="open = false"></div>
<aside class="sidebar" :class="{ 'is-open': open }">
<div class="sidebar-header">
<span class="sidebar-title">Menu</span>
<button class="sidebar-close" @click="open = false">✕</button>
</div>
<div class="sidebar-body">
<nav class="sidebar-nav">
<a class="sidebar-link is-active" href="#">Dashboard</a>
<a class="sidebar-link" href="#">Profile</a>
<a class="sidebar-link" href="#">Settings</a>
</nav>
</div>
</aside>
</div><aside class="sidebar sidebar-right" id="my-sidebar-right">
...
</aside><!-- Wrap page in .sidebar-layout -->
<div class="sidebar-layout">
<aside class="sidebar sidebar-push" id="push-sidebar">
<div class="sidebar-header">...</div>
<div class="sidebar-body">...</div>
</aside>
<div class="sidebar-content">
<!-- page content -->
</div>
</div><aside class="sidebar sidebar-fullpage" id="fullpage-menu">
<div class="sidebar-header">...</div>
<div class="sidebar-body">...</div>
</aside><div class="sidebar-layout">
<div class="sidebar-content"><!-- page --></div>
<aside class="sidebar sidebar-push sidebar-right" id="right-panel">
...
</aside>
</div><div class="sidebar-layout">
<aside class="sidebar sidebar-push sidebar-mini is-open" id="mini-rail">
<!-- header: brand logo + sidebar-mini-toggle button -->
<!-- body: sidebar-link with <span class="sidebar-link-text">Label</span> -->
</aside>
<div class="sidebar-content">...</div>
</div>
<!-- Expand/collapse -->
sidebarExpandToggle('mini-rail')<!-- .is-expanded via a binding — sidebarExpandToggle() not needed -->
<div class="sidebar-layout" x-data="{ wide: false }">
<aside class="sidebar sidebar-push sidebar-mini is-open" :class="{ 'is-expanded': wide }">
<!-- header: brand logo + toggle -->
<button class="sidebar-mini-toggle" @click="wide = !wide">⇔</button>
<!-- body: sidebar-link with <span class="sidebar-link-text">Label</span> -->
</aside>
<div class="sidebar-content">...</div>
</div><aside class="sidebar sidebar-floating" id="my-float">
...
</aside>
<div class="sidebar-backdrop" id="my-float-backdrop"></div>sidebarOpen('id')
sidebarClose('id')
sidebarToggle('id')
sidebarExpandToggle('id') sidebarOpen('my-sidebar') // open overlay
sidebarClose('my-sidebar') // close overlay
sidebarToggle('my-sidebar') // toggle open/close
sidebarExpandToggle('mini-rail') // expand/collapse mini sidebar/* The same API in Alpine — state instead of function calls */
x-data="{ open: false }" // one boolean per sidebar
:class="{ 'is-open': open }" // on .sidebar
:class="{ 'is-visible': open }" // on .sidebar-backdrop
@click="open = true" // sidebarOpen
@click="open = false" // sidebarClose
@click="open = !open" // sidebarToggle
@keydown.escape.window="open = false" // Escape to close
x-data="{ wide: false }" // mini rail
:class="{ 'is-expanded': wide }" // sidebarExpandToggle_notifications.css.
<!-- Toast: success | error | warning | info -->
<!-- Slides in from bottom-right, auto-dismisses, stackable -->
<button onclick="njxFireToast(type, title, message)">Show Toast</button>
njxFireToast("success", "Deployed!", "Your changes are live ✓");
njxFireToast("error", "Error 500", "Server failed to respond");
njxFireToast("warning", "Low storage", "Only 120MB remaining");
njxFireToast("info", "New update", "v1.0.7 is available");<!-- Same .lib-toast classes — Alpine manages the stack, showToast() not needed -->
<div x-data="{
toasts: [], id: 0,
fire(msg, type) {
const t = { id: ++this.id, msg, type };
this.toasts.push(t);
setTimeout(() => this.dismiss(t.id), 2200);
},
dismiss(id) { this.toasts = this.toasts.filter(t => t.id !== id); }
}">
<button class="btn btn-primary btn-sm" @click="fire('Saved!', 'success')">Success</button>
<button class="btn btn-ghost btn-sm" @click="fire('Error occurred', 'error')">Error</button>
<div id="lib-toast-container">
<template x-for="t in toasts" :key="t.id">
<div class="lib-toast" :class="'lib-toast-' + t.type"
@click="dismiss(t.id)" x-text="t.msg"></div>
</template>
</div>
</div>Click any icon to trigger a toast
<div style="position:relative" id="njxBellWrap">
<button class="njx-bell-btn" onclick="njxToggleBell()">🔔
<span class="njx-bell-badge" id="njxBellBadge">4</span>
</button>
<div class="njx-notif-dropdown" id="njxBellDropdown">
<div class="njx-notif-item unread" onclick="njxReadNotif(this)">
<div class="njx-notif-avatar">A</div>
<div class="njx-notif-body">
<div class="njx-notif-text"><b>alex_dev</b> pushed to main</div>
<div class="njx-notif-time">2 min ago</div>
</div>
</div>
</div>
</div>
/* njxToggleBell() — open/close dropdown
njxReadNotif(el) — mark single item read
njxMarkAllRead() — mark all read, clear badge */<!-- Alpine state in the markup: items[], computed unread, outside click -->
<div style="position:relative" @click.outside="open = false" x-data="{
open: false,
items: [
{ id: 1, who: 'alex_dev', text: 'pushed to main', time: '2 min ago', read: false },
{ id: 2, who: 'mona', text: 'commented on PR #38', time: '1 h ago', read: false },
],
get unread() { return this.items.filter(n => !n.read).length },
}">
<button class="njx-bell-btn" @click="open = !open">🔔
<span class="njx-bell-badge" x-show="unread > 0" x-text="unread"></span>
</button>
<div class="njx-notif-dropdown" :class="{ open }">
<template x-for="n in items" :key="n.id">
<div class="njx-notif-item" :class="{ unread: !n.read }" @click="n.read = true">
<div class="njx-notif-avatar" x-text="n.who[0].toUpperCase()"></div>
<div class="njx-notif-body">
<div class="njx-notif-text"><b x-text="n.who"></b> <span x-text="n.text"></span></div>
<div class="njx-notif-time" x-text="n.time"></div>
</div>
</div>
</template>
<button class="njx-inbox-action-btn" @click="items.forEach(n => n.read = true)">✓✓ Mark all read</button>
</div>
</div><!-- njx-ni-success | njx-ni-error | njx-ni-warning | njx-ni-info | njx-ni-dark -->
<div class="njx-notif-inline njx-ni-success">
<span class="njx-notif-inline-icon">✅</span>
<div class="njx-notif-inline-body">
<div class="njx-notif-inline-title">Deployment successful</div>
<div class="njx-notif-inline-msg">Version 1.0.6 is live.</div>
</div>
<button class="njx-notif-inline-close" onclick="njxDismissAlert(this)">×</button>
</div>
/* njxDismissAlert(btn) — collapses parent alert smoothly */
/* njxRestoreAlerts() — restores all dismissed alerts */<!-- x-show + x-collapse-style transition — njxDismissAlert() not needed -->
<div class="njx-notif-inline njx-ni-success" x-data="{ show: true }" x-show="show"
x-transition.duration.250ms>
<span class="njx-notif-inline-icon">✅</span>
<div class="njx-notif-inline-body">
<div class="njx-notif-inline-title">Deployment successful</div>
<div class="njx-notif-inline-msg">Version 1.0.6 is live.</div>
</div>
<button class="njx-notif-inline-close" @click="show = false">×</button>
</div><div class="njx-inbox">
<div class="njx-inbox-header">
<div class="njx-inbox-title">Messages <span class="badge badge-primary" id="njxMsgBadge">3</span></div>
<div class="njx-inbox-actions">
<button class="njx-inbox-action-btn" onclick="njxMarkAllMsgs()">✓✓</button>
</div>
</div>
<div class="njx-msg-item unread" onclick="njxReadMsg(this)">
<div class="njx-msg-avatar">A</div>
<div class="njx-msg-content">
<div class="njx-msg-top">
<span class="njx-msg-name">alex_dev</span>
<span class="njx-msg-time">2m</span>
</div>
<div class="njx-msg-subject">Re: PR #38</div>
<div class="njx-msg-preview">Looks great! One question...</div>
</div>
<div class="njx-msg-dot"></div>
</div>
</div>
/* njxReadMsg(el) — mark message read, update badge
njxMarkAllMsgs() — mark all read */<!-- messages[] in x-data — badge and dots are just bindings -->
<div class="njx-inbox" x-data="{
msgs: [
{ id: 1, who: 'alex_dev', subj: 'Re: PR #38', preview: 'Looks great! One question...', time: '2m', read: false },
{ id: 2, who: 'mona', subj: 'Design review', preview: 'Updated the mockups —', time: '1h', read: false },
],
get unread() { return this.msgs.filter(m => !m.read).length },
}">
<div class="njx-inbox-header">
<div class="njx-inbox-title">Messages
<span class="badge badge-primary" x-show="unread > 0" x-text="unread"></span>
</div>
<div class="njx-inbox-actions">
<button class="njx-inbox-action-btn" @click="msgs.forEach(m => m.read = true)">✓✓</button>
</div>
</div>
<template x-for="m in msgs" :key="m.id">
<div class="njx-msg-item" :class="{ unread: !m.read }" @click="m.read = true">
<div class="njx-msg-avatar" x-text="m.who[0].toUpperCase()"></div>
<div class="njx-msg-content">
<div class="njx-msg-top">
<span class="njx-msg-name" x-text="m.who"></span>
<span class="njx-msg-time" x-text="m.time"></span>
</div>
<div class="njx-msg-subject" x-text="m.subj"></div>
<div class="njx-msg-preview" x-text="m.preview"></div>
</div>
<div class="njx-msg-dot" x-show="!m.read"></div>
</div>
</template>
</div><!-- notification: is-primary | is-success | is-warning | is-danger -->
<div class="notification is-success">
<button class="delete is-small" onclick="this.closest('.notification').style.display='none'"></button>
Completed successfully
</div><!-- Dismiss via x-show — no inline style juggling -->
<div class="notification is-success" x-data="{ show: true }" x-show="show" x-transition.duration.200ms>
<button class="delete is-small" @click="show = false"></button>
Completed successfully
</div><!-- message: is-primary | is-success | is-warning | is-danger -->
<div class="message is-primary">
<div class="message-header">
Header
<button class="delete is-small"></button>
</div>
<div class="message-body">Message text</div>
</div><!-- loader: default | loader-accent | loader-success | loader-lg | loader-xl -->
<div class="loader"></div>
<div class="loader loader-accent"></div>
<div class="loader loader-success"></div>
<div class="loader loader-lg"></div>
<div class="loader loader-xl"></div><!-- Scroll-only: swipe/drag, fade edges hint -->
<div class="scroll-carousel-wrap">
<div class="scroll-carousel">
<div style="min-width:260px">Card 1</div>
<div style="min-width:260px">Card 2</div>
<div style="min-width:260px">Card 3</div>
</div>
</div>
/* CSS: scroll-snap-type: x mandatory on container */
/* each child: scroll-snap-align: start */
/* ::before/::after fade edges via mask */<div class="snap-carousel">
<div style="height:170px">Slide 1</div>
<div style="height:170px">Slide 2</div>
<div style="height:170px">Slide 3</div>
</div>
/* scroll-snap-type: x mandatory, each child: flex: 0 0 100% scroll-snap-align: center */<!-- peek-carousel-wrap adds side padding to reveal next card edge -->
<div class="peek-carousel-wrap">
<div class="peek-carousel">
<div style="height:160px">Card 1</div>
<div style="height:160px">Card 2</div>
<div style="height:160px">Card 3</div>
</div>
</div><!-- Vertical scroll snap — set height on wrapper and each child -->
<div class="scroll-carousel-v" style="height:180px">
<div style="height:180px">Row 1</div>
<div style="height:180px">Row 2</div>
<div style="height:180px">Row 3</div>
</div><!-- JS Carousel: arrows OUTSIDE .js-carousel so overflow:hidden does not block them -->
<div class="js-carousel-wrap">
<div style="position:relative">
<div class="js-carousel">
<div class="js-carousel-track">
<div>Slide 1</div>
<div>Slide 2</div>
<div>Slide 3</div>
</div>
</div>
<button class="js-carousel-btn js-prev" aria-label="Previous">&#�;</button>
<button class="js-carousel-btn js-next" aria-label="Next"> ›</button>
</div>
<div class="js-dots">
<button class="js-dot is-active"></button>
<button class="js-dot"></button>
<button class="js-dot"></button>
</div>
</div><!-- Alpine drives the same track transform — njx.js carousel not needed -->
<div class="js-carousel-wrap" x-data="{ i: 0, n: 3 }">
<div style="position:relative">
<div class="js-carousel">
<div class="js-carousel-track"
:style="'transform: translateX(-' + (i * 100) + '%)'">
<div>Slide 1</div>
<div>Slide 2</div>
<div>Slide 3</div>
</div>
</div>
<button class="js-carousel-btn js-prev" aria-label="Previous"
@click="i = (i - 1 + n) % n"></button>
<button class="js-carousel-btn js-next" aria-label="Next"
@click="i = (i + 1) % n"></button>
</div>
<div class="js-dots">
<template x-for="d in n" :key="d">
<button class="js-dot" :class="{ 'is-active': i === d - 1 }"
@click="i = d - 1"></button>
</template>
</div>
</div><!-- Autoplay: add data-autoplay="ms" to .js-carousel-wrap -->
<!-- Pauses on mouseenter, resumes on mouseleave -->
<div class="js-carousel-wrap" data-autoplay="3000">
<div class="js-carousel">
<div class="js-carousel-track">
<div>Slide 1</div>
<div>Slide 2</div>
</div>
<button class="js-carousel-btn js-prev" aria-label="Previous"></button>
<button class="js-carousel-btn js-next" aria-label="Next"></button>
</div>
<div class="js-dots">
<button class="js-dot is-active"></button>
<button class="js-dot"></button>
</div>
</div><!-- Autoplay with Alpine: setInterval in x-init, pauses on hover -->
<div class="js-carousel-wrap"
x-data="{ i: 0, n: 2, t: null,
start() { this.t = setInterval(() => this.i = (this.i + 1) % this.n, 3000) } }"
x-init="start()" @mouseenter="clearInterval(t)" @mouseleave="start()">
<div class="js-carousel">
<div class="js-carousel-track" :style="'transform:translateX(-' + (i * 100) + '%)'">
<div>Slide 1</div>
<div>Slide 2</div>
</div>
</div>
<div class="js-dots">
<template x-for="d in n" :key="d">
<button class="js-dot" :class="{ 'is-active': i === d - 1 }" @click="i = d - 1"></button>
</template>
</div>
</div><div class="hero-slider" id="mySlider">
<div class="hero-slider-track" id="myTrack">
<div class="hero-slider-slide" style="background:linear-gradient(135deg,#001830,#002a50)">
<div class="hero-slider-body">
<div class="hero-slider-label">Label</div>
<div class="hero-slider-title">Slide Title</div>
<div class="hero-slider-desc">Description text here.</div>
<button class="btn btn-primary btn-sm">CTA</button>
</div>
</div>
<!-- more .hero-slider-slide items -->
</div>
<div class="hero-slider-nav">
<button class="hero-slider-btn" id="myPrev">‹</button>
<button class="hero-slider-btn" id="myNext">›</button>
</div>
<div class="hero-slider-dots" id="myDots"></div>
<div class="hero-slider-progress" id="myProgress"></div>
</div>
<script>
(() => {
const track = document.getElementById("myTrack");
const n = track.children.length;
const INTERVAL = 4500;
const progressEl = document.getElementById("myProgress");
const dotsEl = document.getElementById("myDots");
let cur = 0;
for (let i = 0; i < n; i++) {
const d = document.createElement("button");
d.className = "hero-slider-dot" + (i === 0 ? " is-active" : "");
d.dataset.i = i;
d.addEventListener("click", () => { goTo(+d.dataset.i); resetAuto(); });
dotsEl.appendChild(d);
}
function goTo(idx) {
cur = (idx + n) % n;
track.style.transform = "translateX(-" + (cur * 100) + "%)";
dotsEl.querySelectorAll(".hero-slider-dot").forEach((d, i) => d.classList.toggle("is-active", i === cur));
resetProgress();
}
function resetProgress() {
progressEl.style.transition = "none"; progressEl.style.width = "0%";
requestAnimationFrame(() => requestAnimationFrame(() => {
progressEl.style.transition = "width " + INTERVAL + "ms linear";
progressEl.style.width = "100%";
}));
}
let timer = setInterval(() => goTo(cur + 1), INTERVAL);
function resetAuto() { clearInterval(timer); timer = setInterval(() => goTo(cur + 1), INTERVAL); }
document.getElementById("myPrev").onclick = () => { goTo(cur - 1); resetAuto(); };
document.getElementById("myNext").onclick = () => { goTo(cur + 1); resetAuto(); };
resetProgress();
})();
</script><!-- Same .hero-slider classes — Alpine state instead of the inline script -->
<div class="hero-slider"
x-data="{ i: 0, n: 3, iv: 4500, timer: null,
go(idx) { this.i = (idx + this.n) % this.n; this.prog(); },
prog() { const p = this.$refs.progress;
p.style.transition = 'none'; p.style.width = '0%';
requestAnimationFrame(() => requestAnimationFrame(() => {
p.style.transition = 'width ' + this.iv + 'ms linear';
p.style.width = '100%'; })); },
reset() { clearInterval(this.timer);
this.timer = setInterval(() => this.go(this.i + 1), this.iv); } }"
x-init="prog(); timer = setInterval(() => go(i + 1), iv)"
@mouseenter="clearInterval(timer)" @mouseleave="reset()">
<div class="hero-slider-track" :style="'transform:translateX(-' + (i * 100) + '%)'">
<div class="hero-slider-slide" style="background:linear-gradient(135deg,#001830,#002a50)">
<div class="hero-slider-body">
<div class="hero-slider-label">Label</div>
<div class="hero-slider-title">Slide Title</div>
<div class="hero-slider-desc">Description text here.</div>
<button class="btn btn-primary btn-sm">CTA</button>
</div>
</div>
<!-- more .hero-slider-slide items -->
</div>
<div class="hero-slider-nav">
<button class="hero-slider-btn" @click="go(i - 1); reset()">‹</button>
<button class="hero-slider-btn" @click="go(i + 1); reset()">›</button>
</div>
<div class="hero-slider-dots">
<template x-for="d in n" :key="d">
<button class="hero-slider-dot" :class="{ 'is-active': i === d - 1 }" @click="go(d - 1); reset()"></button>
</template>
</div>
<div class="hero-slider-progress" x-ref="progress"></div>
</div><div class="testi-slider" id="ts">
<div class="testi-track" id="tsTrack">
<div class="testi-slide">
<div class="testi-stars">★★★★★</div>
<div class="testi-quote">Your review text here...</div>
<div class="testi-user">
<div class="testi-avatar" style="background:color-mix(in srgb,var(--color-primary) 16%,transparent);color:var(--color-primary)">A</div>
<div>
<div class="testi-name">Name</div>
<div class="testi-role">Role · Location</div>
</div>
</div>
</div>
<!-- more .testi-slide items -->
</div>
</div>
<div class="testi-controls">
<div class="testi-nav">
<button class="testi-btn" id="tsPrev">‹</button>
<button class="testi-btn" id="tsNext">›</button>
</div>
<div class="testi-counter" id="tsCnt">1 / 3</div>
</div>
<script>
(() => {
const track = document.getElementById("tsTrack");
const n = track.children.length;
const counter = document.getElementById("tsCnt");
let cur = 0;
function goTo(idx) {
cur = (idx + n) % n;
track.style.transform = "translateX(-" + (cur * 100) + "%)";
counter.textContent = (cur + 1) + " / " + n;
}
document.getElementById("tsPrev").onclick = () => goTo(cur - 1);
document.getElementById("tsNext").onclick = () => goTo(cur + 1);
// Swipe
let sx = 0;
track.parentElement.addEventListener("touchstart", (e) => { sx = e.touches[0].clientX; }, { passive: true });
track.parentElement.addEventListener("touchend", (e) => {
const dx = e.changedTouches[0].clientX - sx;
if (Math.abs(dx) > 40) goTo(dx < 0 ? cur + 1 : cur - 1);
});
})();
</script><!-- Same .testi-* classes — Alpine drives the track, counter and swipe -->
<div x-data="{ i: 0, n: 3, sx: 0 }">
<div class="testi-slider"
@touchstart.passive="sx = $event.touches[0].clientX"
@touchend="const dx = $event.changedTouches[0].clientX - sx;
if (Math.abs(dx) > 40) i = (i + (dx < 0 ? 1 : -1) + n) % n">
<div class="testi-track" :style="'transform:translateX(-' + (i * 100) + '%)'">
<div class="testi-slide">
<div class="testi-stars">★★★★★</div>
<div class="testi-quote">Your review text here...</div>
<div class="testi-user">
<div class="testi-avatar">A</div>
<div>
<div class="testi-name">Name</div>
<div class="testi-role">Role · Location</div>
</div>
</div>
</div>
<!-- more .testi-slide items -->
</div>
</div>
<div class="testi-controls">
<div class="testi-nav">
<button class="testi-btn" @click="i = (i - 1 + n) % n">‹</button>
<button class="testi-btn" @click="i = (i + 1) % n">›</button>
</div>
<div class="testi-counter" x-text="(i + 1) + ' / ' + n">1 / 3</div>
</div>
</div><!-- Autoplay strip: duplicate items for seamless loop -->
<div class="autoplay-strip-wrap">
<div class="autoplay-strip">
<div class="autoplay-strip-item">⚡ Buttons</div>
<div class="autoplay-strip-item">🎨 Themes</div>
<div class="autoplay-strip-item">🃏 Cards</div>
<!-- ...more items... -->
<!-- duplicate the same set again for seamless loop -->
<div class="autoplay-strip-item">⚡ Buttons</div>
<div class="autoplay-strip-item">🎨 Themes</div>
<div class="autoplay-strip-item">🃏 Cards</div>
</div>
</div>
/* CSS: animation: njxAutoScroll 20s linear infinite */
/* hover pauses: .autoplay-strip:hover { animation-play-state: paused } */.scroll-carousel-wrap — fade edges.scroll-carousel — scrollable track.js-carousel-wrap — outer containerdata-autoplay="ms" — autoplay.js-carousel — viewport (overflow:hidden).js-carousel-track — sliding track.js-carousel-btn — arrow button.js-prev / .js-next — direction.js-dots — dot container.js-dot — single dot.is-active — active dot state.carousel-item-sm — 160px.carousel-item-md — 260px.carousel-item-lg — 360px.carousel-item-xl — 480px<!-- 1. CSS scroll-only — simplest, no JS -->
<div class="scroll-carousel-wrap">
<div class="scroll-carousel">
<div style="min-width:300px">Card 1</div>
<div style="min-width:300px">Card 2</div>
</div>
</div>
<!-- 2. JS sequential — arrows outside overflow:hidden wrapper -->
<div class="js-carousel-wrap">
<div style="position:relative">
<div class="js-carousel">
<div class="js-carousel-track">
<div>Slide 1</div>
<div>Slide 2</div>
</div>
</div>
<button class="js-carousel-btn js-prev" aria-label="Previous">‹</button>
<button class="js-carousel-btn js-next" aria-label="Next">›</button>
</div>
<div class="js-dots">
<button class="js-dot is-active"></button>
<button class="js-dot"></button>
</div>
</div>
<!-- 3. JS autoplay — add data-autoplay="ms" -->
<div class="js-carousel-wrap" data-autoplay="3000">...</div>
_social.css. Flexible social icon links — 6 variants with hover effects, brand colors, pills, glass and more.