# NoJS Elements Complete Documentation > NoJS Elements is a UI element plugin library for the No.JS HTML-first reactive framework. 17 declarative, accessible components — zero JavaScript required from developers. Everything is driven by HTML attributes. Requires No.JS >= 1.13.0. NoJS Elements provides drag-and-drop, form validation, tooltips, popovers, modals, dropdowns, toasts, tabs, trees, steppers, skeletons, split panes, sortable tables, accordions, breadcrumbs, scroll spy, and virtual lists. When loaded via CDN ` ``` ## Usage ### ESM ```javascript import NoJS from '@erickxavier/no-js'; import NoJSElements from '@erickxavier/nojs-elements'; NoJS.use(NoJSElements); ``` ### CDN (Script Tag) When loaded via ` ``` ## Peer Dependency This plugin requires **No.JS >= 1.13.0** as a peer dependency. ## Elements Overview | Element | Directives | Description | |---------|-----------|-------------| | Drag & Drop | `drag`, `drop`, `drag-list`, `drag-multiple` | Declarative drag-and-drop with sortable lists and multi-select | | Form Validation | `validate`, `validate-on`, `validate-if`, `$form` | Declarative form validation with per-rule errors and `$form` context | | Tooltip | `tooltip` | Positioned tooltips with configurable delay and placement | | Popover | `popover`, `popover-trigger`, `popover-dismiss` | Rich content popovers with trigger and dismiss controls | | Modal | `modal`, `modal-open`, `modal-close` | Accessible dialog modals with focus trap and backdrop | | Dropdown | `dropdown`, `dropdown-toggle`, `dropdown-menu`, `dropdown-item` | Keyboard-navigable dropdown menus | | Toast | `toast-container`, `toast` | Notification toasts with position, type, duration, and auto-dismiss | | Tabs | `tabs`, `tab`, `panel`, `tab-disabled`, `tab-position` | Accessible tabbed interfaces with keyboard navigation | | Tree | `tree`, `branch`, `subtree`, `tree-drag-mode` | Collapsible tree views with nested branches and drag-and-drop | | Stepper | `stepper`, `step`, `stepper-validate` | Multi-step wizards with validation gate and progress indicators | | Skeleton | `skeleton` | Loading placeholder skeletons | | Split / Pane | `split`, `pane` | Resizable split panels (horizontal or vertical) | | Sortable Table | `sortable`, `sort`, `fixed-header`, `fixed-col`, `table-reorder` | Column sorting with fixed headers, columns, and row reorder | | Accordion | `accordion` | Animated expand/collapse on native `
` elements | | Breadcrumb | `breadcrumb` | Accessible breadcrumb trail with manual or auto-track mode | | Scroll Spy | `spy`, `spy-offset`, `spy-threshold` | Highlights navigation links based on visible sections | | Virtual List | `virtual-height`, `virtual-buffer` | Efficient rendering of large datasets with DOM virtualization | --- # Drag and Drop > The DnD module is included in NoJS Elements. When using the CDN, it is auto-installed — no separate registration is needed. For ESM usage, call `NoJS.use(NoJSElements)` once. ## `drag` — Make an Element Draggable ```html
Drag me
Task card
⠁⠁
Locked item
``` ### Drag Attributes | Attribute | Type | Default | Description | |-----------|------|---------|-------------| | `drag` | expression | *required* | The value being dragged | | `drag-type` | string | `"default"` | Named type — only matching `drop-accept` zones respond | | `drag-effect` | `"copy"` \| `"move"` \| `"link"` | `"move"` | Maps to `dataTransfer.effectAllowed` | | `drag-handle` | CSS selector | — | Restricts the grab area to a child element | | `drag-image` | CSS selector \| `"none"` | — | Custom drag ghost element | | `drag-image-offset` | `"x,y"` | `"0,0"` | Pixel offset for custom drag image | | `drag-disabled` | expression | `false` | When truthy, disables dragging | | `drag-class` | string | `"nojs-dragging"` | Class added while dragging | | `drag-ghost-class` | string | — | Class added to the drag image element | | `drag-group` | string | — | Group name for multi-select | --- ## `drop` — Define a Drop Zone ```html
Drop tasks here
Max 3 items
``` ### Drop Attributes | Attribute | Type | Default | Description | |-----------|------|---------|-------------| | `drop` | statement | *required* | Expression executed on drop | | `drop-accept` | string (comma-separated) | `"default"` | Accepted `drag-type`(s). Use `"*"` for any | | `drop-effect` | `"copy"` \| `"move"` \| `"link"` | `"move"` | Maps to `dataTransfer.dropEffect` | | `drop-class` | string | `"nojs-drag-over"` | Class added when valid item hovers | | `drop-reject-class` | string | `"nojs-drop-reject"` | Class added when item is rejected (wrong type or max exceeded) | | `drop-disabled` | expression | `false` | When truthy, disables dropping | | `drop-max` | expression (number) | `Infinity` | Max items the zone accepts | | `drop-sort` | `"vertical"` \| `"horizontal"` \| `"grid"` | — | Enables sortable reorder by position | | `drop-placeholder` | template ID \| `"auto"` | — | Shows a placeholder at insertion point | | `drop-placeholder-class` | string | `"nojs-drop-placeholder"` | Class for the placeholder | | `drop-settle-class` | string | `"nojs-drop-settle"` | Custom CSS class for the settle animation | | `drop-empty-class` | string | `"nojs-drag-list-empty"` | Custom CSS class for empty state on drop zone | --- ## Element-Level Events (`drag`/`drop`) The `drag` and `drop` directives dispatch CustomEvents on their host elements at each stage of the drag-and-drop lifecycle. Listen with `on:`. | Event | Bubbles | `$event.detail` | Description | |-------|---------|-----------------|-------------| | `drag-start` | yes | `{ item, index, el }` | Fired on the `[drag]` element when a drag begins | | `drag-end` | yes | `{ item, index, dropped }` | Fired on the `[drag]` element when the drag ends. `dropped` is `true` if the item was successfully dropped | | `drag-enter` | no | `{ item, type }` | Fired on the `[drop]` zone when a valid draggable enters it | | `drag-leave` | no | `{ item }` | Fired on the `[drop]` zone when the draggable leaves | | `drag-over` | no | `{ item, index }` | Fired on a sortable `[drop]` zone as the item moves over it. `index` is the current insertion position | | `drop` | no | `{ item, index, source, target, effect }` | Fired on the `[drop]` zone after the drop expression executes. `source`/`target` contain `{ list, index, el }` | ```html
Drag me
Drop here
``` --- ## `drag-list` — Sortable List High-level shorthand for sortable lists bound to arrays. Combines `each` + `drag` + `drop` in one element. ```html
``` ### Drag-List Attributes | Attribute | Type | Default | Description | |-----------|------|---------|-------------| | `drag-list` | path | *required* | Path to array in state | | `template` | template ID | — | Template for each item (same as `each`) | | `drag-list-key` | property name | — | Unique key per item for stable identity | | `drag-list-item` | variable name | `"item"` | Loop variable name in template | | `drop-sort` | `"vertical"` \| `"horizontal"` \| `"grid"` | `"vertical"` | Layout direction | | `drop-accept` | string | *self* | Types accepted (defaults to same list only) | | `drag-list-copy` | boolean attr | — | Copy items instead of moving | | `drag-list-remove` | boolean attr | — | Remove items when dragged out | | `drag-disabled` | expression | `false` | Disables dragging from this list | | `drop-disabled` | expression | `false` | Disables dropping into this list | | `drop-max` | expression (number) | `Infinity` | Max items allowed | | `drop-settle-class` | string | `"nojs-drop-settle"` | Custom CSS class for the settle animation | | `drop-empty-class` | string | `"nojs-drag-list-empty"` | Custom CSS class for empty state on drag-list | | `drop-placeholder` | template ID \| `"auto"` | — | Shows a placeholder where the item will be dropped | ### Drag-List Events | Event | `$event.detail` | Description | |-------|-----------------|-------------| | `on:reorder` | `{ list, item, from, to }` | Item reordered within same list | | `on:receive` | `{ list, item, from, fromList }` | Item received from another list | | `on:remove` | `{ list, item, index }` | Item removed (dragged out) | --- ## `drag-multiple` — Multi-Select Enables click-to-select before dragging multiple items as a group. ```html
``` | Attribute | Type | Default | Description | |-----------|------|---------|-------------| | `drag-multiple` | boolean attr | — | Enables click-to-select | | `drag-multiple-class` | string | `"nojs-selected"` | Class added to selected items | | `drag-group` | string | *required* | Group name — all selected items move together | - **Click** selects a single item (replaces previous selection) - **Ctrl/Cmd+Click** adds to selection - **Escape** clears the selection - When dragging a selected item, `$drag` becomes an **array** of all selected items --- ## Implicit Variables Available inside `drop` expressions: | Variable | Type | Description | |----------|------|-------------| | `$drag` | any | The dragged value. Array if multi-select | | `$dragType` | string | The `drag-type` of the item | | `$dragEffect` | string | The `drag-effect` | | `$dropIndex` | number | Insertion index within the drop zone | | `$source` | object \| null | `{ list, index, el }` — source info | | `$target` | object \| null | `{ list, index, el }` — target info | --- ## CSS Classes No.JS automatically injects these classes: | Class | When applied | |-------|-------------| | `.nojs-dragging` | On the source element while dragging | | `.nojs-drag-over` | On the drop zone while a valid item hovers | | `.nojs-drop-reject` | On the drop zone when the item is rejected (wrong type or max exceeded) | | `.nojs-drop-placeholder` | On the insertion placeholder | | `.nojs-selected` | On multi-selected items | | `.nojs-drop-settle` | Brief settle animation on drop | | `.nojs-drag-list-empty` | On a `drag-list` when it has no items | --- ## Accessibility No.JS automatically adds: - `draggable="true"` on drag sources - `aria-grabbed="true/false"` reflecting drag state - `aria-dropeffect` on drop zones - `role="listbox"` on `drag-list` containers - `role="option"` on `drag-list` items - `tabindex="0"` for keyboard access - **Space** to grab, **Escape** to cancel, **Arrow keys** to navigate, **Enter** to drop --- # Validation > The Validation module is included in NoJS Elements. When using the CDN, it is auto-installed — no separate registration is needed. For ESM usage, call `NoJS.use(NoJSElements)` once. ## `
` — Form-Level Validation Add `validate` to a `` to enable declarative form validation. Creates a `$form` context object that tracks validity, dirty/touched state, errors, and values for all named fields inside the form. ```html
``` Native browser validation popups are disabled automatically (`novalidate` is set on the form). ### Form Attributes | Attribute | Type | Default | Description | |-----------|------|---------|-------------| | `validate` | boolean attr | *required* | Enables form-level validation and creates `$form` context | | `validate-on` | string | `"input change focusout"` | Space-separated list of events that trigger validation (form-wide default) | | `error-class` | string | — | CSS class applied to invalid fields (form-wide default, overridden per-field) | --- ## `$form` Context API Inside any `
`, the `$form` object is available in expressions. ### Properties | Property | Type | Description | |----------|------|-------------| | `$form.valid` | boolean | `true` when all fields pass validation. Reflects real validity regardless of touched/dirty state | | `$form.dirty` | boolean | `true` when any field value has changed | | `$form.touched` | boolean | `true` when any field has been focused and blurred | | `$form.submitting` | boolean | `true` during the submit event handler (auto-resets on next frame) | | `$form.pending` | boolean | `true` when any async validators are in-flight | | `$form.errors` | object | Map of field name to error message — only includes errors for interacted (touched or dirty) fields | | `$form.values` | object | Map of field name to current value. Checkbox fields map to `true`/`false` | | `$form.firstError` | string \| null | The first error message (among interacted fields), or `null` | | `$form.errorCount` | number | Number of interacted fields with errors | | `$form.fields` | object | Per-field state objects (see below) | ### Methods | Method | Description | |--------|-------------| | `$form.reset()` | Resets dirty/touched state, clears pending validators, calls native `form.reset()`, and re-validates | ### Per-Field State (`$form.fields.`) Each named field gets a state object accessible via `$form.fields.`: | Property | Type | Description | |----------|------|-------------| | `valid` | boolean | `true` when this field passes all rules | | `dirty` | boolean | `true` when this field's value has changed | | `touched` | boolean | `true` when this field has been focused and blurred | | `error` | string \| null | The highest-priority error message, or `null` | | `value` | any | Current field value | ```html

``` --- ## Field Validation Rules ### `validate` Attribute Add to ``, `