Documentation
Complete list of Sprinkle directives, usage examples, and guides.
autosize
On: <textarea>
<textarea autosize placeholder="Type here — it grows…"></textarea>auto-width
On: <input>, <textarea>
<input auto-width placeholder="Full width input" />clearable
On: <input>
<input clearable placeholder="Search…" />character-count
On: <input>, <textarea>
<input character-count maxlength="16" />auto-select
On: <input>
<input value="https://…" auto-select readonly />enter-submit
On: <textarea>
<textarea enter-submit></textarea>drop-zone
On: <label> wrapping <input type="file">. Supports drag-and-drop, click to browse, image preview, multiple files, and removal.
Single image (avatar):
Multiple files (any type):
<label drop-zone>
<span>Drag your avatar here or click to browse</span>
<input type="file" name="avatar" accept="image/*" />
</label>leading / suffix
On: <input>
<input leading="search" />
<input type="password" leading="lock" suffix="eye" />prefix
On: <input type="url">
<input type="url" prefix />
<input type="url" prefix="upper.do" />combo-box
On: <select>
With leading / suffix icons:
Multi-select with multiple:
With category groups:
<select combo-box searchable>
<option value="1" data-avatar="…">Upper Platform</option>
<option value="2" data-avatar="…" selected>Nimbus Runtime</option>
<option value="3" data-avatar="…">Forge Core</option>
</select>error-message
On: any validated element
<input required error-message-required="Can't be blank." />allowed-domains
On: <input type="email|url">
<input type="email" allowed-domains="upper.do,example.com" />mask
On: <input type="tel|text">
<input type="tel" mask />
<input type="text" mask="00/00/0000" />no-past / no-future
On: <input type="date|datetime-local">
<input type="date" no-past />
<input type="date" no-future />disable-days
On: <input type="date|datetime-local">
<input type="date" disable-days="weekends" />business-hours
On: <input type="datetime-local">
<input type="datetime-local" business-hours="09:00-18:00" />date-range
On: <input type="date|datetime-local">. Add date-input to enable the custom calendar picker with dual-month range view.
<input type="date" date-input date-range="trip" data-range-type="start" />
<input type="date" date-input date-range="trip" data-range-type="end" />date-input
On: <input type="date|datetime-local">. Replaces the native date picker with a custom calendar popup featuring month/year navigation, disabled date support, keyboard navigation (arrows, PageUp/Down, Home/End, Enter/Space, Escape), and full ARIA accessibility. When combined with date-range, displays two side-by-side months.
<input type="date" date-input />
<!-- With constraints -->
<input type="date" date-input no-past />
<input type="date" date-input disable-days="weekends" />
<!-- Range mode -->
<input type="date" date-input date-range="trip" data-range-type="start" />
<input type="date" date-input date-range="trip" data-range-type="end" />drawer
On: <dialog>
<dialog drawer="left" close-outside id="nav">…</dialog>
<button command-for="nav" command="show-modal">Open</button>modal
On: <dialog>
<dialog modal id="confirm">
<div class="sprinkle-modal-header">…</div>
…
</dialog>shell + sidebar + nav + content
The page itself uses shell with sidebar="left" and content. Below is a second nested layout example — no inline styles, no extra classes:
Welcome to the Dashboard
This nested shell uses the same shell grid with sidebar + nav. The sidebar width and content padding come from sprinkle defaults.
card
On: <fieldset>
Basic card with <legend>:
<fieldset card>
<legend>Profile</legend>
<main>
<p>Name: Jane Doe</p>
</main>
</fieldset>Card with <header>, <main>, and <footer>:
<fieldset card>
<header>Notifications</header>
<main>
<p>You have 3 unread messages.</p>
</main>
<footer>
<button loading>Mark all read</button>
</footer>
</fieldset>Clickable card with href:
<fieldset card href="/sprinkle">
<header>Forge Sprinkle</header>
<main>…</main>
<footer>
<a href="/sprinkle" class="card-link">Learn more →</a>
</footer>
</fieldset>Grid of cards:
<div style="display:grid;…">
<fieldset card>
<header>Getting Started</header>
<main>…</main>
</fieldset>
…
</div>count-up
On: any element, <progress>
Animates from start (default 0) to the element's text value using IntersectionObserver.
<strong count-up duration="2500">7,342</strong>
<span count-up duration="2000">12,847</span>
<span count-up start="90" duration="1500">99.97%</span>On <progress> — animates the value attribute:
<progress count-up value="2500" max="3000"></progress>
<span count-up duration="2000">2,500</span> / 3,000 GBaccordion
On: <details>
What is ForgeSprinkle?
A set of HTML attribute enhancements. Each directive is self-contained and degrades gracefully.
Does it require a build step?
No. Drop in the CSS and JS files. No bundler, no npm, no configuration.
What about accessibility?
Uses native <details> semantics. aria-expanded is handled automatically.
<details accordion="faq">
<summary>Question</summary>
<p>Answer.</p>
</details>dropdown
On: <details>
My Account
<details dropdown close-outside>
<summary>My Account</summary>
<ul>
<li><a href="#">Profile</a></li>
<li><a href="#">Logout</a></li>
</ul>
</details>close-outside
On: <details>, <dialog>
Click me
Click outside to close this panel.
<details close-outside>
<summary>Click me</summary>
<p>Click outside to close.</p>
</details>open-group / close-group
On: <button>
Item A
Content A
Item B
Content B
<button open-group="faq">Expand all</button>
<button close-group="faq">Collapse all</button>sticky
On: any element
Scroll down to see the sticky element catch.
It should be stuck at the top of this box now.
More content to ensure scrolling.
<div sticky>I stick to the top.</div>zoomable
On: <img>
<img src="photo.jpg" zoomable />copy / copy="#id"
On: any element
<button copy>Copy my label</button>
<input value="hello@example.com" copy />loading
On: <button>
<button loading>Save</button>switch
On: <input type="checkbox">
<input type="checkbox" switch />truncate="N"
On: any element
This is a long paragraph that gets clamped to two lines. The "Show more" button appears at the end of the clamped text. Clicking it reveals the full content, and clicking "Show less" collapses it back. This pattern is useful for card previews, article excerpts, and comment threads where you want to show a preview before expanding. This is especially handy when you have variable-length content and want a consistent card height.
<p truncate="2">Long text…</p>tooltip
On: any element
<button tooltip="This cannot be undone">Delete</button>
<span tooltip="Verified account">✅ Verified</span>avatar
On: <img>
<img avatar="sm" />
<img avatar />
<img avatar="lg" />breadcrumb
On: <ul>
<ul breadcrumb>
<li><a href="#">Home</a></li>
<li>Current Page</li>
</ul>confirm-leave
On: <form>
<form confirm-leave>
<textarea></textarea>
</form>otp
On: <input>
<input type="number" min="6" max="6" otp />enhance
On: <form>
Ajax form submission with loading states, validation errors, and server response handling.
<form enhance method="post" action="/api/submit">
<input name="email" type="email" required />
<button loading>Submit</button>
</form>theme-toggle
On: any element
Toggles data-sprinkle-theme between light and dark on click. Persists to localStorage.
Click the sun icon button at the top of this page to toggle the theme.
<button theme-toggle>
<svg>…</svg>
</button>Icons
Place SVGs in /assets/svg/{name}.svg. Reference by name (no extension):
<input leading="search" placeholder="Search…" />
<input type="password" leading="lock" suffix="eye" />Visibility toggle: suffix on type="password" swaps between {name}.svg and {name}-off.svg on click.
Clear button: suffix="close" or suffix="clear" clears the input on click.
Custom path: Override the SVG directory with a <meta> tag:
<meta name="sprinkle-svg-path" content="/custom/path/to/icons">When suffix is present, clearable is ignored.
Accessibility
aria-live="polite"on character counters and drop-zone announcementsaria-expandedon truncate toggles and accordion summariesrole="switch"andaria-checkedon switch togglesrole="alert"andaria-describedbyon validation errorsrole="tooltip"on tooltip elements- WAI-ARIA combobox pattern on
[combo-box]:role="combobox",role="listbox",role="option",aria-expanded,aria-haspopup,aria-multiselectable,aria-selected,aria-posinset,aria-setsize aria-current="page"automatically set on active links inul[nav]aria-labelon drop-zone remove buttons- Keyboard navigation on OTP (arrow keys, backspace, auto-advance)
- Native
<details>/<summary>keyboard behavior preserved in dropdown mode
Extending
Custom directives can be added via the global ForgeSprinkle namespace:
ForgeSprinkle.register('my-attr', function (el) {
el.style.border = '2px solid gold'
})Register before DOMContentLoaded. The handler runs on matching elements at init and on dynamically added elements via MutationObserver.