More capable HTML. Ordinary forms.
html+ provides framework-independent form controls and core UI primitives. Components handle interaction, value formats, and form participation. Your application supplies the data, business rules, and workflows. ADR-0007 records that boundary: an IBAN field checks format and check digits, while the application verifies the account and starts the payment.
Status: prototype. Element names and APIs may still change, and the h6- prefix is provisional. There is no npm package: npm i htmlplus installs an unrelated third-party package. The name htmlplus.dev is reserved and not live yet.
Try it: project site · form playground · styling gallery
No package is published yet, so build a tarball from a clone. Requires Node.js 22 or later and npm.
git clone https://github.com/sebastian-software/htmlplus.git
cd htmlplus
npm ci
npm packThen install htmlplus-0.1.0.tgz in your project. A Git dependency does not work, because the built files are ignored in Git. The name htmlplus in these examples is a placeholder until the package name is decided.
To explore the source instead, run npm run dev. The project site is at http://127.0.0.1:4173/, the playground at http://127.0.0.1:4173/demo/, and the gallery at http://127.0.0.1:4173/demo/styling.html. Refresh the page after source changes.
Import an element once and use it in ordinary markup. Importing registers it, so there is nothing else to call.
import "htmlplus/iban";
import "htmlplus/tags";
import "htmlplus/switch";<form>
<label for="account">IBAN</label>
<h6-iban id="account" name="iban" required></h6-iban>
<label for="topics">Topics</label>
<h6-tags id="topics" name="topics" value='["html", "forms"]'></h6-tags>
<label for="updates">Product updates</label>
<h6-switch id="updates" name="updates" value="email"></h6-switch>
<button>Submit</button>
</form>new FormData(form) and native submission receive the values, and labels, validation, reset, and disabled fieldsets work as with native fields. Forms and validation covers showing errors and using the elements with React.
| Import | What it does |
|---|---|
htmlplus/<name>, such as htmlplus/date-picker |
Registers that element and exports its class |
htmlplus |
Registers all twenty-four elements and exports their classes |
htmlplus/react |
JSX types for React 19 |
htmlplus/native.css, themes.css, shadcn.css |
The optional stylesheets |
Each entry is safe to import during server rendering, where it does nothing. Without a bundler, use the prebuilt modules in browser/, such as <script type="module" src="/htmlplus/browser/elements/iban.js"></script>. Keep that folder together with its chunks/, and keep THIRD_PARTY_NOTICES.txt with the distributed modules.
Each element has a built-in neutral base, so no stylesheet is required. Customize it with inherited --hp-* tokens, CSS parts, and ordinary CSS on wrapped native fields. Optional themes.css adds Light/Dark palettes, shadcn.css connects an existing shadcn theme, and native.css styles h6-field and <button class="hp-button"> without JavaScript. See the styling guide.
There are twenty-one form controls using ElementInternals, plus Accordion, Tabs, and Native Field, which submit nothing themselves. Fifteen elements use Zag's vanilla adapter internally; there is no runtime component framework. The element reference lists each element's attributes, properties, methods, and parts.
| Element | Behavior | Reference |
|---|---|---|
h6-field |
Shared base styling around a real light-DOM input, textarea, or select | API |
h6-switch |
On/off setting with a checkbox-like form value | API |
h6-checkbox |
Independent checked and mixed states; checkbox-like submission | API |
h6-toggle |
Pressed button with a checkbox-like form contribution | API |
h6-iban |
Grouped display, whitespace-free submission, ten national formats, and check digits | API |
h6-bic |
Uppercase submission and 8- or 11-character structure checks | API |
h6-otp |
Character slots over one native editor, autofill hints, and preserved leading zeros | API |
h6-password-input |
Native password editing and a keyboard-accessible visibility button | API |
h6-number-input |
Localized editing, canonical numeric submission, constraints, and stepping | API |
h6-duration |
Notation such as 1h 30m or 01:30, submitted as whole seconds |
API |
h6-interval |
Two numeric editors with named boundaries and optional open ends | API |
h6-slider |
One bounded number by pointer or keyboard | API |
h6-range-slider |
Two stable thumbs with explicitly named form entries | API |
h6-rating |
Clearable whole score, hover preview, and an unanswered state | API |
h6-segmented |
Compact single selection using native radio inputs | API |
h6-radio-group |
One identifier with descriptions and disabled options | API |
h6-toggle-group |
Single or multiple selection with repeated form entries | API |
h6-select |
Single selection from supplied options in a top-layer listbox | API |
h6-combobox |
Searchable selection; query text never becomes a form entry | API |
h6-tags |
Add and remove tags that submit as repeated entries | API |
h6-date-picker |
Localized editor and calendar with strict date-only submission | API |
h6-date-range-picker |
Two editors, range selection, and two named ISO entries | API |
h6-accordion |
Disclosure sections; contained fields keep their own form values | API |
h6-tabs |
Linked panels; contained fields keep their own form values | API |
Actions stay real buttons: the native Button family is <button class="hp-button"> styled by native.css.
html+ targets current stable Chromium, Firefox, and Safari. CI runs all three engines through Playwright. Exact minimum versions are unverified.
The elements rely on these platform features:
- Custom elements, shadow DOM, and
ElementInternals, on every form control. ElementInternals.statesand:state(), for live state on the controls that expose it.- The Popover API, on Select, Combobox, Date Picker, and Date Range Picker. There is no older-browser fallback.
- CSS
light-dark()andcolor-mix(), in surface shadows and derived colors. document.execCommand("insertText"), as a fallback role only. It keeps native undo while IBAN and OTP format text. If the command is unavailable or fails, ordinary native editing, canonical values, and validation keep working. See formatted fields.
Physical devices, OTP autofill, password managers, manual assistive-technology combinations, and real browser history restoration are unverified. Automated axe checks and a Playwright WebKit pass don't establish them.
Element sizes lists what each element costs on its own, from about 2 KB gzipped for h6-switch to about 50 KB for h6-date-range-picker. All twenty-four elements together are about 120 KB, and importing only the ones a page uses keeps the rest out of its bundle.
Text fields are IBAN, BIC, OTP, Duration, Number Input, and Password Input. Their shared rules are below, along with the contracts for Switch, BIC, and Tags, which have no separate guide. Other elements are described in the guides linked from the element table.
- Text fields expose canonical
.value, raw.displayValue, and.defaultValue. An IBAN displaysDE89 3704 0044 0532 0130 00while the form receivesDE89370400440532013000. Enter submits the form like a native field. Enter that chooses a Combobox option or commits a tag does not submit. - Assignment is programmatic and emits no user events.
nullorundefinedempties a string.value; other values useString(). Properties assigned before an element upgrades are applied when it connects. - Events: host
inputandchangebubble and are composed. - Reset restores defaults and clears
data-touched. Explicit custom errors remain until cleared withsetCustomValidity(""). See forms and validation. - Switch exposes
.checked,.defaultChecked, and.value(defaulton). An unchecked switch contributes no entry. It supportsdisabled, notreadonly. - BIC normalizes case and whitespace and keeps the entered 8- or 11-character form, without adding or removing a branch identifier.
- Tags expose
.valueand.defaultValueas string arrays; declarative defaults use a JSON array in thevalueattribute. Entries are trimmed and deduplicated with case-sensitive equality, in order. Enter, comma, or blur commits pending text. Backspace in an empty editor focuses the last remove button. Editing an existing tag in place is not implemented. - Format checks are local. They don't establish account ownership, BIC registration, or authentication-code validity.
- IBAN coverage is AT, BE, CH, DE, ES, FR, GB, IE, IT, and NL. A well-formed IBAN from any other country fails validation with
patternMismatchand blocks submission. The profiles are hand-authored format rules checked against Swift Registry release 103, not a bundled copy of the registry.
<h6-duration name="duration" value="1h 30m" min="60"></h6-duration>
<h6-interval name="budget" lower-name="budget_min" upper-name="budget_max"
value="[200,800]" min="0" max="10000" step="50" required></h6-interval>
<h6-segmented name="delivery" value="standard" required>
<option value="economy">Economy</option>
<option value="standard">Standard</option>
<option value="express">Express</option>
</h6-segmented>- Duration:
.valueis seconds as a string, and.displayValueis the editor text. Bare integers are seconds.HH:MM[:SS]means hours, minutes, and optional seconds; units accept wholeh,m, andsin that order. Fractions, negatives, unsafe integers, and calendar units are rejected.minandmaxare in seconds; empty attributes are ignored. An optional empty field submits an empty string, like a native text input. - Interval:
.valueand.defaultValueare[number | null, number | null]; a JSONvalueattribute declares defaults. A hostnameenables submission; keys default toname.minandname.maxunlesslower-nameandupper-nameoverride them.lower-labelandupper-labelset the visible boundary labels (default From and To). Blank boundaries are omitted, andrequiredrequires both. Both inputs usemin,max, andstep(native default step: 1); ordering is validated without swapping.readonlyallows inspection without editing. Restoration preserves the raw numeric editor strings. - Segmented:
.valueand.defaultValueare strings. Direct child options follow native defaults for values and labels; the first duplicate value wins. Unknown or disabled selections report"", are omitted, and return with their option.requiredneeds an enabled selection. Options can be added, removed, or updated. Native radio arrow keys and Space select; a label click focuses the selected option. Usedisabledfor a noninteractive choice.
All three support ordinary form association, fieldset disabling, reset, setCustomValidity, checkValidity, and reportValidity. Programmatic assignments emit no user events.
The custom form controls depend on JavaScript. There is no no-JavaScript fallback for them and no server-rendering integration: elements render no Declarative Shadow DOM, and the modules read document on import, so they can't be imported in a server runtime. A server can still emit the element tags and attributes for the browser to upgrade.
Native Field and the Button family keep native behavior without JavaScript, and native.css supplies their base appearance. Accordion and Tabs keep their sections in light DOM, so that content is present before upgrade.
Before upgrade, an element has no shadow root or layout, and child <option> elements can show as plain text. html+ ships no pre-upgrade CSS. Use :defined to reserve space and hide raw options, adjusting the selectors to the elements you use:
:is(h6-iban, h6-select, h6-combobox):not(:defined) {
display: block;
min-height: var(--hp-control-height, 2.5rem);
}
:is(h6-select, h6-combobox, h6-segmented, h6-radio-group, h6-toggle-group):not(:defined) > option {
display: none;
}This is ordinary CSS and the project's tests don't exercise it.
Using the elements
- Element reference: generated attributes, properties, methods, and parts for each element.
custom-elements.jsonholds the same data for tools. - Forms and validation: showing errors, validity flags per element, replacing messages, and framework use.
- Styling: tokens, parts, states, presets, and the shadcn adapter.
- Native fields: styled native input, textarea, and select.
- Everyday controls: Checkbox, Radio Group, Toggle Group, Number Input, Password Input, and native buttons.
- Formatted fields: IBAN and OTP presentation and editing.
- Interaction elements: Toggle, Accordion, and Tabs.
- Numeric choices: Slider, Range Slider, and Rating.
- Select and Combobox: identifiers, queries, options, and popups.
- Date Picker and Date Range Picker: ISO values, parsing, and calendars.
- Locale formatting: inherited language, Intl dates and numbers, and week information.
The project
- Project plan: status, open decisions, and next steps.
- Architecture decisions: current rationale and browser evidence.
- Playground design: layout and styling intent of the demo.
- Glossary: shared field terminology.
- Changelog: user-visible changes.
See CONTRIBUTING.md for setup, checks, adding an element, and deployment, and SECURITY.md to report a vulnerability. Repository conventions are in AGENTS.md.
html+ is licensed under the Apache License 2.0. Bundled dependencies are listed in the third-party notices.