Farvist docs

A lightweight (~21 KB), Sass-powered glassmorphism CSS framework. Frosted surfaces, neon glow, gradients and a free backgrounds library — generated from design tokens with @for / @each loops.

MIT Zero dependencies No build step Dark + light

Installation

Drop in one stylesheet — no build step. Add the optional 8.5 KB (gzip) script for modals, tabs, toasts and the theme toggle.

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/farvist/dist/farvist.min.css">
<script src="https://cdn.jsdelivr.net/npm/farvist/assets/farvist.js" defer></script>

Three builds v1.7

Swap the filename in the CDN URL. All three share the same tokens, skins and class names — the docs apply unchanged.

FileGzipWhat's inside
farvist.min.css~21 KBEverything — all 42 components, utilities, backgrounds, skins.
farvist-slim.min.css~19 KBThe framework without the 11 AI-interface components (chat, prompt, status, prose, tool-call, reasoning, command palette, diff, suggestions, attachment, snippet) — for sites that never render AI conversations.
farvist-ai.min.css~6.6 KBOnly the AI-interface kit (plus tokens, skins, buttons, avatars, icons, toasts) — an add-on for sites already on Tailwind, Bootstrap or custom CSS. No reset, no grid, no utilities; assumes box-sizing: border-box and a browser-default 16px root (the kit is rem-sized); on a light host page wrap the UI in data-theme="light". Tailwind v3 hosts: also load farvist-ai-compat.css after your Tailwind build — v3's un-layered preflight otherwise strips the kit's borders and button styling. Bootstrap hosts need it too — unconditionally. The kit’s own buttons carry class="btn", and Bootstrap’s .btn is un-layered, so it wins: measured against Bootstrap 5.3.3, the send button and every .btn-glass lose their padding, weight, radius, glass fill and border, and button text drops to 1.2:1 on a dark page. The compat file restores all of it. Tailwind v4's preflight is layered and needs nothing. Live demo →

Or build from the Sass source to customize the tokens — @use only the partials you need for a truly minimal sheet:

npm install
npm run dev   # → dist/farvist(.min).css, farvist-slim, farvist-ai

Theming

Everything is driven by --fv-* custom properties. The default is the dark glass theme; add data-theme="light" to <html> to flip every surface at runtime — no recompile.

document.documentElement.setAttribute('data-theme', 'light'); // or remove for dark

Bring your brand — no build step v1.3

Every derived color — gradients, neon glows, mesh backdrops, the body orbs, button hover/active states, soft badge tints, focus rings — now derives from the --fv-* custom properties at runtime. Override a handful of variables and the whole framework re-brands, straight off the CDN:

:root {
  --fv-primary: #10b981;   /* your brand */
  --fv-accent:  #a3e635;
  --fv-info:    #2dd4bf;

  /* optional companions when your brand flips brightness: */
  --fv-primary-text: #6ee7b7;      /* readable tint for text/links on the dark surface */
  --fv-primary-contrast: #06281d;  /* text on primary-filled buttons/badges */
}

Same for --fv-success, --fv-danger, --fv-warning, --fv-secondary — each accepts an optional --fv-{color}-contrast. Derivations use color-mix(), which is already in Farvist's browser baseline. This also means your AI assistant can re-brand a page by writing five lines of CSS. Prefer a visual tool? Open the Theme Builder →

Skins — prebuilt theme packs v1.4

Five named skins ship built-in, each a small token block on the same data-theme attribute (and each contrast-gated to WCAG AA in CI). Try them on this page:

<html data-theme="synthwave">          <!-- markup… -->
Farvist.theme('synthwave');            // …or JS (persists in localStorage)
<button data-fv-theme-cycle="synthwave,cyber,noir,forest,dawn">Skin</button>

Semantic colors (success / danger / warning) stay constant across skins on purpose — a red error stays red everywhere. Add your own skin by extending the $skins map in Sass, or ship a [data-theme="yourbrand"] block of --fv-* overrides in plain CSS.

Re-theme at build time by configuring the module:

@use 'farvist/scss/farvist' with (
  $primary: #00e0ff,
  $accent:  #ff4dd2,
  $glass-blur: 22px
);

Add a key to the $theme-colors map and you instantly get .btn-*, .badge-*, .text-*, .bg-* and more for it — that's the payoff of generating from maps.

Cascade layers — easy overrides

Farvist's CSS is wrapped in cascade layers — @layer reset, base, layout, components, utilities — so utilities beat components by layer order, not !important. The practical win: any CSS you write outside a layer beats all of Farvist, no specificity battles or !important needed.

/* your stylesheet, loaded after farvist.css */
.btn { border-radius: 0; }     /* unlayered → wins over Farvist's .btn */

Prefer to keep your overrides organized? Put them in your own layer after utilities.

Browser support: the shipped CSS is autoprefixed (PostCSS + Autoprefixer). Everything works in Chrome/Edge 111+, Safari 16.4+, Firefox 113+ (~early 2023); older browsers degrade gracefully — glass falls back to an opaque surface via @supports, and the color-mix status pulse simply doesn't animate. Full matrix in the readme.

Grid

A 12-column flexbox grid with responsive breakpoints (sm md lg xl xxl).

.col-md-8
.col-md-4
<div class="row gy-2">
  <div class="col-12 col-md-8">…</div>
  <div class="col-12 col-md-4">…</div>
</div>

Utilities

Single-purpose helper classes, all generated from the token maps. Most take an optional breakpoint infix — {prop}-{sm|md|lg|xl}-{value} — that applies from that width up (d-md-flex, text-lg-center, col-md-6).

Spacing

Margin (m) and padding (p) on a 0–8 scale, per side: {m|p}{t|e|b|s|x|y}-{0–8}. x=left+right, y=top+bottom, blank=all sides; s/e are start/end (RTL-aware). mx-auto centers.

Step012345678
rem0.25.5.7511.5234

.mt-3 .px-4 .p-0 .my-6 .ms-auto .gap-3 .m-md-5

Sizing

.w-25 .w-50 .w-75 .w-100 .w-auto · .h-25.h-100 · .mw-100 (max-width) · .mh-100 (max-height)

Display

.d-none .d-block .d-inline .d-inline-block .d-flex .d-inline-flex .d-grid .d-table — each with breakpoints, so .d-none.d-md-block hides on phones, shows from md up.

Flexbox & alignment

.flex-row .flex-column .flex-wrap .flex-nowrap .flex-fill · .justify-content-{start|center|end|between|around|evenly} · .align-items-{start|center|end|baseline|stretch} · .align-self-* · .order-{0–5} · .gap-{0–8}

ABC
<div class="d-flex justify-content-between align-items-center gap-2">…</div>

Typography

Size .fs-xs .fs-sm .fs-base .fs-lg .fs-xl .fs-2xl .fs-3xl .fs-4xl .fs-5xl · Weight .fw-light .fw-normal .fw-medium .fw-semibold .fw-bold .fw-black · Line height .lh-1 .lh-base .lh-lg

Align .text-start .text-center .text-end (+ breakpoints) · Transform .text-uppercase .text-lowercase .text-capitalize · Wrap .text-truncate .text-nowrap .text-break

Colors

.text-{color}, .bg-{color} and .border-{color} for every theme color. All resolve from the runtime --fv-* variables, so they follow a re-brand.

primarysecondarysuccessdangerwarninginfoaccent

Gradient text .text-gradient .text-gradient-accent .text-gradient-sunset .text-gradient-aurora

Borders & radius

.border .border-0 .border-{top|end|bottom|start} .border-{color} · .rounded .rounded-{sm|md|lg|xl|2xl} .rounded-pill .rounded-circle .rounded-0

Position & layering

.position-{static|relative|absolute|fixed|sticky} · z-index tokens .z-dropdown .z-sticky .z-fixed .z-modal .z-tooltip · .overflow-{auto|hidden|scroll|visible}

Effects

.shadow-{sm|md|lg|xl} .shadow-none · neon .glow .glow-{color} · .opacity-{0…100} (steps of 10) · .hover-lift (raise on hover) · .animate-float (gentle bob, reduced-motion safe)

Coming from Bootstrap

If you know Bootstrap, you already know most of Farvist. The grid, spacing, display, flex and colour utilities use the same class names on purpose — a lot of Bootstrap markup is drop-in. Here's what carries over and what differs.

AreaBootstrapFarvistCompatibility
Grid.row .col-md-6.row .col-md-6identical
Spacing.mt-3 .px-4.mt-3 .px-4same, scale goes to 8
Display / flex.d-flex .justify-content-between.d-flex .justify-content-betweenidentical
Buttons.btn .btn-primary .btn-lg.btn .btn-primary .btn-lgidentical
Cards, alerts.card .card-body · .alert-info.card .card-body · .alert-infoidentical
Text & colour.text-center .text-muted .bg-primary.text-center .text-muted .bg-primaryidentical
Badges.badge .bg-primary.badge .badge-primaryrenamed
ModalJS plugin + data-bs-*native <dialog> + data-fv-opensimpler
ThemingSass rebuildoverride --fv-* at runtimeno build step

The big wins on top: a glass aesthetic, a free backgrounds library, an AI component kit, and runtime re-branding — none of which need a build step.

Backgrounds free · exclusive

Mesh gradients, patterns, spotlights and fade-masks — one class each. The headline feature Tailwind and Bootstrap make you hand-roll.

.bg-mesh-aurora
.bg-mesh-nebula .bg-drift
.bg-grid .bg-fade
.bg-spotlight-accent
<section class="bg-mesh-aurora">…</section>        <!-- mesh gradient -->
<div class="bg-grid bg-fade">…</div>              <!-- pattern, faded at edges -->
<header class="bg-spotlight-primary">…</header>   <!-- radial glow -->

Meshes: aurora · sunset · ocean · nebula. Patterns: grid · graph · dots · lines · noise. Modifiers: .bg-fade (put on a decorative layer — it masks children too), .bg-drift (animate a mesh).

Buttons

<button class="btn btn-primary">Primary</button>
<button class="btn btn-gradient-primary">Gradient</button>
<button class="btn btn-outline-accent">Outline</button>

Colors: primary secondary success danger warning info accent light dark. Sizes .btn-sm / .btn-lg; full-width .btn-block.

Cards & badges

Glass card

Frosted surface with an inner highlight.

badge solid
<article class="card card-glow">
  <div class="card-body">
    <h3 class="card-title">Glass card</h3>
    <p class="card-text">…</p>
  </div>
</article>

Forms

<label class="form-label">Email</label>
<input class="form-control" type="email">

Modal · Tabs · Toast

These three use the optional JS companion. Modal is a native <dialog>; accordion and dropdown are pure CSS (<details>).

<button data-fv-open="#m">Open</button>
<dialog class="modal" id="m"> … </dialog>

Farvist.toast({ title: 'Saved', variant: 'success' });

Command palette v1.5

The ⌘K menu every modern dev tool and AI app has — type-to-filter, full keyboard nav, and a combobox/listbox ARIA pattern, built on the native <dialog>. Press ⌘K / Ctrl K anywhere on this page, or:

  • Jump to
  • Buttons
  • Theming
  • Chat & AI kit
  • Utilities
  • Links
  • Theme Builder
  • GitHub
navigate select esc close

Each .command-item carries data-fv-command — a URL/anchor to navigate to, or any string, which fires an fv:command event you can handle for custom actions. Add data-fv-keywords to match on synonyms.

<button data-fv-open="#cmd">Search <kbd>⌘K</kbd></button>

<dialog class="command" id="cmd" aria-label="Command menu">
  <div class="command-search">
    <svg class="icon"><use href="…#i-search"/></svg>
    <input class="command-input" placeholder="Type a command…">
  </div>
  <ul class="command-list">
    <li class="command-group">Jump to</li>
    <li class="command-item" data-fv-command="/docs/">
      <svg class="icon">…</svg><span class="command-label">Docs</span>
    </li>
  </ul>
  <div class="command-empty" hidden>No matches.</div>
</dialog>

// custom actions:
document.querySelector('#cmd')
  .addEventListener('fv:command', e => run(e.detail.value));
// or open it yourself: Farvist.command('#cmd')

Feedback

Alerts, callouts and empty states.

Saved
Your changes are live.
Callouts draw the eye to a tip or aside.
📭

Nothing here yet.

<div class="alert alert-success"><div class="alert-heading">Saved</div>…</div>
<div class="callout callout-accent">A tip or aside.</div>
<div class="empty-state"><div class="empty-state-icon">📭</div><p>Nothing yet.</p></div>

Data display

NameStatus
AdaActive
MiraAway
  • Inbox
  • Drafts
8.4k
Users
  • Shipped v0.11
    today
  • Docs polish
    earlier
  1. 1Account
  2. 2Plan
  3. 3Done
<div class="table-responsive"><table class="table table-hover">…</table></div>
<ul class="list-group"><li class="list-group-item">Inbox</li></ul>
<div class="stat-value text-gradient">8.4k</div><div class="stat-label">Users</div>
<ul class="timeline"><li class="timeline-item timeline-primary">
  <div class="timeline-marker"></div><div class="timeline-content">…</div></li></ul>
<ol class="stepper"><li class="step is-active"><span class="step-dot">2</span>…</li></ol>

Indicators

Online Failed
<div class="progress"><div class="progress-bar" style="width:60%"></div></div>
<div class="spinner spinner-primary"></div>
<div class="spinner-dots"><span></span><span></span><span></span></div>
<span class="status status-online">Online</span>
<div class="skeleton skeleton-text"></div>

More inputs

A styled range slider and a JS-free segmented control. (The switch is in Forms.)

<input type="range" class="form-range">
<div class="segmented">
  <input type="radio" id="d" name="seg" checked><label for="d">Day</label>
  <input type="radio" id="w" name="seg"><label for="w">Week</label></div>

Icons & accordion

55 line icons (24×24, sized via font-size or width/height, coloured by currentColor). The AI/chat set is highlighted.

check
x
plus
minus
chevron-down
chevron-right
arrow-right
arrow-left
menu
search
user
users
bell
settings
heart
star
home
mail
lock
eye
download
upload
trash
edit
calendar
clock
info
alert
external
sun
moon
zap
sparkles
code
layers
bot
brain
message
message-dots
cpu
send
mic
stop
refresh
copy
thumbs-up
thumbs-down
wand
paperclip
image
command
terminal
globe
database
link
Is it accessible?
Yes — ARIA is wired up automatically by farvist.js.
Does it need a build step?
No — one <link> and you're set.
<svg class="icon"><use href="assets/icons/farvist-icons.svg#i-home"/></svg>
<details class="accordion-item">
  <summary>Question</summary>
  <div class="accordion-body">Answer.</div></details>

Chat & AI kit ✦

Components for AI products — a conversation thread, a prompt composer, agent status, and the model-output layer: rendered markdown (.prose), a streaming caret, tool-call cards, reasoning disclosures, citations, code diffs, prompt suggestions and attachments. See the full AI console template, or the same kit driving an operator UI in the trading bot and AI cluster consoles.

Chat thread

How can I help?
Assistant · now
Scaffold a pricing page.
You
<div class="chat">
  <div class="message">                  <!-- assistant (left) -->
    <span class="avatar avatar-sm avatar-accent">AI</span>
    <div class="message-body">
      <div class="message-bubble">How can I help?</div>
      <div class="message-meta">Assistant</div>
    </div>
  </div>
  <div class="message message-out"> … </div>   <!-- user (right) -->
</div>
<!-- typing dots -->
<span class="typing"><span></span><span></span><span></span></span>

Prompt composer

0 / 4000

Agent status

Online Thinking Idle Failed

Prose — rendered model output

Bubbles preserve raw newlines (white-space: pre-wrap) for plain text. When you render markdown to HTML, wrap it in .prose (compact: .prose-sm) — it restores normal flow and styles headings, lists, tables and images at content scale.

Two ways to install:

  • CDN — one <link> tag
  • npmnpm i farvist
OptionBest for
CDNprototypes
npmapps with a build
Assistant · rendered markdown
<div class="message-bubble">
  <div class="prose prose-sm"> …rendered markdown HTML… </div>
</div>

Streaming caret & message actions

Add .streaming to a bubble while tokens arrive — a pulsing caret marks live output (static under reduced motion). .message-actions is a copy/vote row that reveals on hover or focus (always visible on touch). A bare data-fv-copy in the row copies the message's bubble text and flashes the button green.

Glass surfaces need a rich backdrop to blur, so give the page a mesh
Assistant · streaming
<div class="message-bubble streaming">…tokens so far…</div>
<div class="message-actions">
  <button class="btn btn-glass btn-sm" data-fv-copy aria-label="Copy">…</button>
</div>

Tool calls

An agent's tool invocation as a compact card. The state classes tint the rail — keep the .tool-call-status text so meaning never relies on colour alone.

fetch_metricsRunning…
{"range": "30d"}
search_docsDone
query: "backgrounds library"
3 sections matched — backgrounds, effects, utilities.
deploy_siteFailed
Error: missing credentials.
<div class="tool-call tool-call-done">
  <div class="tool-call-header">
    <svg class="icon" aria-hidden="true"><use href="…#i-terminal"/></svg>
    <span class="tool-call-name">search_docs</span>
    <span class="tool-call-status">Done</span>
  </div>
  <div class="tool-call-args">query: "backgrounds library"</div>
  <div class="tool-call-result">3 sections matched.</div>
</div>

Reasoning

A collapsible "thinking" disclosure on the native <details> element — keyboard and screen-reader accessible with zero JS.

Thought for 12 seconds
The user wants current data, so search the docs first, then compose the answer from the matched sections.
<details class="reasoning">
  <summary class="reasoning-summary">Thought for 12 seconds</summary>
  <div class="reasoning-body">…model thinking…</div>
</details>

Citations

Superscript .cite chips link claims to a .sources footnote list — the RAG answer pattern.

Glass surfaces need a rich backdrop to blur1, so give the page a mesh background2.

  1. docs/backgrounds — why glass needs a backdrop
  2. llms-full.txt — conventions
…to blur<a class="cite" href="#src-1">1</a>
<ol class="sources">
  <li id="src-1"><a href="…">docs/backgrounds</a></li>
</ol>

Diff view v1.6

The code-change display AI coding assistants live in. The +/ characters stay in the content, so meaning never rides on colour alone; the tints follow the runtime tokens.

src/theme.css +1 −1
@@ -1,3 +1,3 @@
  :root {
-   --fv-primary: #6d4af5;
+   --fv-primary: #10b981;
<div class="diff">
  <div class="diff-header">src/theme.css
    <span class="diff-stat"><span class="diff-stat-add">+1</span> <span class="diff-stat-del">−1</span></span></div>
  <pre class="diff-body"><code><span class="diff-line diff-hunk">@@ -1,3 +1,3 @@</span>
<span class="diff-line diff-del">- old</span>
<span class="diff-line diff-add">+ new</span></code></pre>
</div>

Suggestions & attachments v1.6

Prompt-starter chips (.suggestion) and file pills (.attachment) for the composer.

quarterly-report.pdf2.4 MB

<div class="suggestions">
  <button class="suggestion">Summarize this page</button>
</div>

<span class="attachment">
  <svg class="icon">…#i-paperclip</svg>
  <span class="attachment-name">report.pdf</span>
  <span class="attachment-meta">2.4 MB</span>
  <button class="attachment-remove" aria-label="Remove report.pdf">&times;</button>
</span>

Named code blocks v1.6

Give a snippet the filename bar assistants use for generated files — hand-author the wrap and farvist.js still adds the copy button.

app.jsjavascript
Farvist.toast({ title: 'Deployed', variant: 'success' });
<div class="snippet-wrap">
  <div class="snippet-header">
    <span class="snippet-title">app.js</span>
    <span class="snippet-lang">javascript</span></div>
  <pre class="snippet"><code>…</code></pre>
</div>

Streaming messages (JS)

Farvist.stream(el, text) types text into an element with the .streaming caret and re-runs enhance() when done (instant under reduced motion). Or inject markup yourself and call Farvist.enhance().

await Farvist.stream(bubble, 'Here is the answer, streamed word by word…');

chat.insertAdjacentHTML('beforeend', bubbleHTML);
Farvist.enhance();   // re-run progressive enhancement
Press the button to stream this bubble.

Use Farvist with your AI ✦

Farvist is built to be generated correctly by AI assistants. Point your tool at the machine-readable context, or paste the primer below.

  • llms-full.txt — every convention, component, icon and copy-paste recipe. Paste this into Cursor / Claude / ChatGPT.
  • ai-context.json — machine-readable catalog (components, utilities, icons, recipes).
  • llms.txt — the concise index (llms.txt convention).
  • farvist.cursorrules — drop into your project as .cursorrules.

Paste-in primer

You are an expert in Farvist, a glassmorphism CSS framework.
Prefer Farvist classes (components + utilities) over hand-written CSS.
Dark by default; add data-theme="light" to switch; give the page a
bg-mesh-* background so the glass reads. Colors: primary, accent, success…
(suffixes: btn-primary, text-accent). Spacing 0–7 (p-4 = 1rem).
Icons: <svg class="icon"><use href="…#i-bot"/></svg>.
Full context: https://farvist.com/llms-full.txt

JS companion

~8.5 KB gzip, no dependencies. It auto-applies ARIA to tabs & progress bars and wires these data-attributes:

data-fv-open="#id"      // open a <dialog class="modal">
data-fv-dismiss          // close the nearest dialog
data-fv-tab="#panel"     // switch tabs (arrow-key nav included)
data-fv-theme-toggle     // flip dark / light
data-fv-nav-toggle       // toggle the mobile navbar
<pre class="snippet">   // gets a copy button (or use any [data-fv-copy])

Farvist.toast({ title, message, variant, timeout });
Farvist.copy(text);      // copy text to the clipboard
Farvist.enhance();       // re-wire after injecting DOM dynamically

Accessibility

Farvist aims to be accessible by default. The optional farvist.js companion progressively enhances your markup on load, adding the ARIA that's tedious to hand-write — drop it in and most of the list below is automatic.

Automatic (via farvist.js)

  • Tabs — full tablist/tab/tabpanel roles, roving tabindex, arrow-key nav.
  • Progress bars — role="progressbar" + aria-valuenow/min/max.
  • Breadcrumb · stepper · pagination — aria-current on the active item.
  • Forms — .is-invalid gets aria-invalid and is linked to its .invalid-feedback via aria-describedby.
  • Tooltips — the data-tooltip text is exposed to screen readers and shows on keyboard focus.
  • Toasts — announced via a live region; variant:'danger' is assertive (role="alert"), others polite (role="status").
  • Modal — native <dialog> (focus trap + Esc); the navbar hamburger exposes aria-expanded.

Skip link

Make it the first element in <body>; it stays hidden until focused, then pins to the top-left.

<a class="skip-link" href="#main">Skip to content</a>
<main id="main" tabindex="-1"> … </main>

Form validation — try tabbing to the field

Mark the control .is-invalid and put the message in a sibling .invalid-feedback; the JS wires the rest.

Enter a valid email address.
<label class="form-label" for="email">Email</label>
<input class="form-control is-invalid" id="email">
<div class="invalid-feedback">Enter a valid email.</div>
<!-- JS adds aria-invalid + aria-describedby -->

Good to know

  • Tooltips describe, they don't name — give icon-only controls their own aria-label.
  • Pagination — wrap it in <nav aria-label="Pagination"> and label the prev/next arrows.
  • Focus is always visible for keyboard users; restyle it via the --fv-focus-ring token.
  • Reduced motion — animation and transition are suppressed under prefers-reduced-motion: reduce.

Contribute

Farvist is open source (MIT). Issues and PRs welcome. The framework lives under scss/, generated from token maps in scss/abstracts/_variables.scss.

★ Star on GitHub ← Back to the demo