fvn-ui
v0.2.0
Published
Minimalist vanilla JS component library
Downloads
582
Readme
fvn-ui
Minimal vanilla JS component library with layout helpers. Zero dependencies.
🤖 AI/LLM Users: See AGENTS.md for quick reference or LLM.md for complete documentation.
Quick Start
Via CDN
<script src="https://unpkg.com/fvn-ui@latest/dist/ui.js"></script>
<script>
// direct
ui.card()
// or granular
const { card } = window.ui;
</script>Via NPM
npm install fvn-uiWith a bundler (Vite, webpack, esbuild):
import { ui } from 'fvn-ui'
ui.button({ label: 'Save' })
ui.switch({ label: 'Dark mode' })Without a bundler (native ES modules):
import { ui } from 'https://unpkg.com/fvn-ui@latest/dist/ui.esm.js'Tree-shakeable imports (bundler only):
import 'fvn-ui/style.css'
import { button } from 'fvn-ui/button'
import { card } from 'fvn-ui/card'Components
Layout (layout. or direct import)
| Component | Description |
|-----------|-------------|
| row / col | Flexbox containers (grow by default) |
| card | Container with title, description, content |
| dashboard | View management with navigation |
| header | Title + description group |
| title / description | Text primitives |
| label | Form label |
| divider | Horizontal/vertical separator |
Inputs
| Component | Description |
|-----------|-------------|
| button | Buttons with variants, colors, icons |
| checkbox | Checkbox |
| editable | Contenteditable with text input features |
| input / textarea | Text input with label and validation |
| radio | Radio button group |
| select | Dropdown with filter and multiselect |
| switch / toggle | Boolean inputs |
| toggleGroup | Tab-style button group |
Overlays
| Component | Description |
|-----------|-------------|
| modal / tooltip | Dialogs and popovers |
| confirm | Confirmation dialog with trigger |
| collapsible | Expandable sections |
| tabs | Tabbed content |
Media
| Component | Description |
|-----------|-------------|
| avatar | User avatar |
| image | Image with loading states |
| svg | Icon system |
Layout Helpers
Flexbox containers that grow by default to fill parent. Args can be in any order.
import { el, row, col, layout } from 'fvn-ui'
// Basic usage
layout.row([ button({ label: 'A' }), button({ label: 'B' }) ])
layout.col(parent, { gap: 2, children: [...] })
// Alignment shorthands (same for row and col)
row({ start: true }, [...]) // aligned left (default)
row({ center: true }, [...]) // centered
row({ end: true }, [...]) // aligned right
col({ end: true }, [...]) // aligned bottom
// Push child to end
row([
button({ label: 'Cancel' }),
button({ label: 'Save', end: true }) // pushed right
])
// Opt-out of grow
row({ grow: false }, [...]) // shrink to content| Container Props | Description |
|-----------------|-------------|
| gap: 4 | Space between children (0-10, default: 2) |
| start, center, end | Align children on main axis |
| grow: false | Shrink to content |
| Child Props | Description |
|-------------|-------------|
| end: true | Push to end (right in row, bottom in col) |
| start: true | Push to start |
| Spacing Props | Description |
|---------------|-------------|
| padding: 4 | All-around padding (1-10) |
| block: 4 | Vertical padding (1-10) |
| inline: 4 | Horizontal padding (1-10) |
Event Callbacks
All callbacks follow a consistent (value, ...context, event) pattern:
// First arg is always the unwrapped value, last arg is the event
input({ onInput: (value, event) => console.log(value) })
checkbox({ onChange: (checked, event) => ... })
radio({ onChange: (value, item, event) => ... })
select({ onChange: (value, item, event) => ... })
tabs({ onChange: (value, item, event) => ... })
// `this` is bound to the element
input({ onChange(value) { console.log(this.id, value) } })Runtime Limit Updates
input() and editable() support runtime limit updates for validation/counters.
const bio = ui.input({ label: 'Bio', rows: 4, counter: true, min: 10, max: 500 })
bio.setLimits(5, 300)
bio.setLimits({ max: 120 }) // min unchanged
bio.setLimits({ min: null }) // clear min
const notes = ui.editable({ label: 'Notes', counter: true, min: 10, max: 500 })
notes.setLimits({ max: 200 })setLimits(...) accepts (min, max) or { min, max }.
undefined keeps existing bounds, null clears a bound.
Editable Rich + Markdown Mode
editable({ rich: true }) uses the built-in contenteditable rich driver and a minimal fixed toolbar:
heading, bold, italic, quote, list, link, and markdown mode toggle.
const ed = ui.editable({ label: 'Body', rich: true, rows: 6 })
await ed.toggleMarkdownMode() // rich <-> markdown editor
await ed.toMarkdown() // Promise<string>
await ed.toHTML() // Promise<string>valueis mode-dependent:- rich mode: HTML
- markdown mode: markdown
onInput(value, event)/onChange(value, event)emit mode-dependent values.- Link uses one universal button (set URL / clear URL).
- Numbered lists are not supported in toolbar (unordered list only).
toMarkdown()lazily loadsturndownfrom jsDelivr on first use.toHTML()lazily loadsmarkedfrom jsDelivr on first use.
CSS Variables
Common CSS variables available for custom styling. See style.css for full list.
| Variable | Description |
|----------|-------------|
| --space-1 to --space-10 | Spacing scale (used by gap, padding props) |
| --back | Background color |
| --text | Text color |
| --muted | Muted/secondary text |
| --hover | Hover state background |
| --border | Border color |
| --radius | Common border radius |
AI Assistant Setup
When using AI coding assistants with fvn-ui, copy the docs to your project for better discoverability.
Quick Setup (all tools)
# Using npx (recommended)
npx fvn-ui
# Or add to package.json scripts
{
"scripts": {
"docs": "fvn-ui"
}
}This copies AGENTS.md and LLM.md to your project root.
Tool-Specific Rules
Option 1: Repository instructions (recommended)
mkdir -p .github && cp node_modules/fvn-ui/RULES.md .github/copilot-instructions.mdOption 2: VS Code settings (Cmd/Ctrl+Shift+P → "Preferences: Open User Settings (JSON)")
{
"github.copilot.chat.codeGeneration.instructions": [
{ "file": "AGENTS.md" },
{ "file": "LLM.md" }
]
}Copilot also auto-discovers AGENTS.md, CLAUDE.md, and GEMINI.md in project root.
Option 1: Project rules (recommended)
mkdir -p .cursor/rules && cp node_modules/fvn-ui/RULES.md .cursor/rules/fvn-ui.mdOption 2: Legacy .cursorrules (still supported, will be deprecated)
cp node_modules/fvn-ui/RULES.md .cursorrulesOption 3: User rules (Cursor Settings → Rules → add global rules)
Cursor also auto-discovers AGENTS.md in project root and subdirectories.
Option 1: Workspace rules (recommended)
mkdir -p .windsurf/rules && cp node_modules/fvn-ui/RULES.md .windsurf/rules/fvn-ui.mdOption 2: Global rules (applies to all projects)
Create/edit ~/.windsurf/global_rules.md and paste contents of RULES.md.
cp node_modules/fvn-ui/RULES.md CLAUDE.mdClaude looks for CLAUDE.md in project root.
Most AI tools look for AGENTS.md in the project root (already copied above).
If your tool supports custom instructions, point it to LLM.md for complete documentation.
Documentation
Each component has JSDoc with examples. See source files in src/fvn-ui/components/ or example page.
