The components on this site are also available as Web Components: <i80-*> tags that render the same HTML and styles. They need no framework and no build step, so they work in plain HTML and in Django, Flask, Rails or PHP templates.
<link rel="stylesheet" href="https://design.i80.dk/v/0.5.2/components.css">
<script type="module" src="https://design.i80.dk/v/0.5.2/i80.js"></script>
<i80-button color="primary" icon="plus">New plan</i80-button>
Native elements written inside a tag are kept, so server-rendered forms keep their field names, ids, values and CSRF tokens:
<i80-text-input label="Email" error="{{ form.email.errors.0 }}">
{{ form.email }}
</i80-text-input>
See all Web Components with live examples, or a whole screen built from them.
Each component page on this site shows the same thing: on the Code tab, pick .html
to see that example written as HTML.
In a framework
Custom elements are part of the browser, so they work in any framework that renders HTML. What differs is how a framework passes data to them. We test i80 in plain HTML, in server-rendered templates and with HTMX; the notes below are what to expect elsewhere.
| What to do | |
|---|---|
| HTMX, Alpine, Turbo | Nothing. Swapped-in tags are set up as soon as they are inserted. |
| Svelte, Solid, Lit | Nothing. They set properties and attributes on custom elements. |
| React 19 and later | Nothing. React 19 sets properties, and onI80Close-style props are not needed — add listeners with a ref if you want events. |
| React 18 and earlier | String attributes work; for events, attach a listener to a ref. |
| Vue 3 | Tell the compiler these are custom elements, otherwise it warns: compilerOptions.isCustomElement: (tag) => tag.startsWith('i80-'). |
| Angular | Add CUSTOM_ELEMENTS_SCHEMA to the module or component. |
Server-side rendering frameworks (Next.js, Nuxt, Rails with Turbo) render the tags as
plain markup; i80.js upgrades them in the browser. Nothing breaks before it loads,
because a tag's content is real HTML — a form still submits.
React and Vue are not in scope for us yet, so there are no wrapper packages: you use the tags directly. If a product needs deeper integration, that is worth designing then.