Web Component Libraries & CSS Frameworks
WildflowerJS works with any CSS framework and most JavaScript component libraries out of the box. Because there's no virtual DOM and no build step, you can drop in Bootstrap, DaisyUI, Shoelace, or Chart.js the same way you would in a vanilla HTML page.
- No wrappers needed: unlike React/Vue/Angular, you don't need framework-specific wrapper packages
- No build step: link a CDN stylesheet or script tag and you're done
- Real DOM: libraries that read or write the DOM work without conflict
- Standard HTML: CSS frameworks style your elements directly, no JSX translation needed
Compatibility at a Glance
Third-party libraries fall into three categories based on how they integrate:
| Tier | Examples | Setup | Effort |
|---|---|---|---|
| CSS Frameworks Pure styling, zero JavaScript |
DaisyUI, Bootstrap, Bulma, Pico CSS, Open Props, Pure CSS, Beer CSS | Link stylesheet | Zero config |
| JS Libraries DOM-manipulating libraries |
Chart.js, SortableJS, Leaflet, FullCalendar, Flatpickr, Tippy.js, Prism.js | Script tag + init() |
Minimal |
| Web Components Shadow DOM |
Web Awesome, Fluent UI, Nord Health, Shoelace, IBM Carbon | Script tag + adapter | One script tag |
CSS Frameworks (Zero Config)
CSS-only frameworks are the simplest integration. They provide styled components via CSS classes, with no JavaScript runtime, no Shadow DOM, and no conflicts. WildflowerJS's data-bind-class and data-bind-style work perfectly with them.
Recommended: DaisyUI + Tailwind CSS
DaisyUI provides 65+ pre-styled components (buttons, cards, modals, tabs, drawers, etc.) as pure CSS classes built on Tailwind CSS. It has 40K+ GitHub stars, active development, and zero JavaScript overhead.
<!-- Add to your <head> -->
<link href="https://cdn.jsdelivr.net/npm/daisyui@4/dist/full.min.css" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<!-- That's it. Now use DaisyUI classes with WildflowerJS: -->
<div data-component="todo-app">
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h2 class="card-title" data-bind="title"></h2>
<input type="text" class="input input-bordered w-full"
data-model="newItem" placeholder="Add a task...">
<button class="btn btn-primary mt-2" data-action="addItem">
Add Task
</button>
<div class="divider"></div>
<div data-list="items">
<template>
<div class="flex items-center gap-2 py-1">
<input type="checkbox" class="checkbox checkbox-sm"
data-action="toggleItem">
<span data-bind="text"
data-bind-class="done ? 'line-through opacity-50' : ''">
</span>
<button class="btn btn-ghost btn-xs ml-auto"
data-action="removeItem">
×
</button>
</div>
</template>
</div>
<div class="stats shadow mt-4">
<div class="stat">
<div class="stat-title">Remaining</div>
<div class="stat-value text-primary" data-bind="remaining"></div>
</div>
</div>
</div>
</div>
</div>
wildflower.component('todo-app', {
state: {
title: 'My Tasks',
newItem: '',
items: [
{ text: 'Learn WildflowerJS', done: true },
{ text: 'Try DaisyUI components', done: false },
{ text: 'Build something cool', done: false }
]
},
computed: {
remaining() {
return this.items.filter(i => !i.done).length;
}
},
addItem() {
if (!this.newItem.trim()) return;
this.items = [
...this.items,
{ text: this.newItem, done: false }
];
this.newItem = '';
},
toggleItem(event, element) {
const index = element.closest('[data-list-index]')?.dataset.listIndex;
if (index !== undefined) {
const items = [...this.items];
items[index] = { ...items[index], done: !items[index].done };
this.items = items;
}
},
removeItem(event, element) {
const index = element.closest('[data-list-index]')?.dataset.listIndex;
if (index !== undefined) {
this.items = this.items.filter((_, i) => i !== parseInt(index));
}
}
});
btn, card, input, checkbox, stats classes style standard HTML elements. WildflowerJS handles reactivity; DaisyUI handles appearance. No conflicts possible.
Other CSS Frameworks
| Framework | Components | Approach | CDN Size | Notes |
|---|---|---|---|---|
| Bootstrap 5 | 30+ | CSS classes + optional JS | ~25 KB | Most popular. JS components (dropdowns, modals) work alongside WildflowerJS. |
| Bulma | 40+ | Pure CSS | ~26 KB | Zero JavaScript. Flexbox-based. Clean, modern aesthetic. |
| Pico CSS | 20+ | Classless + semantic | ~10 KB | Styles native HTML elements automatically. Minimal classes needed. |
| Open Props | N/A | CSS custom properties | ~5 KB | Design tokens, not components. Pairs with any approach. |
| Pure CSS | 15+ | Pure CSS modules | ~4 KB | Yahoo's minimal CSS toolkit. Extremely lightweight. |
| Beer CSS | 40+ | CSS classes | ~15 KB | Material Design 3 aesthetic. No build tools required. |
All of these work by adding a <link> tag to your page. No adapters, no configuration, no conflicts.
JavaScript Libraries (Minimal Setup)
DOM-manipulating JavaScript libraries — charting, mapping, drag-and-drop, date pickers, rich text editors — integrate naturally because WildflowerJS uses the real DOM. Initialize them in your component's init() method and sync state changes with watchers.
The General Pattern
wildflower.component('my-widget', {
state: {
libraryInstance: null,
data: []
},
init() {
// 1. Initialize the library on a DOM element
this.libraryInstance = new SomeLibrary(
this.element.querySelector('#target'),
{ data: this.data }
);
// 2. Library events → update WildflowerJS state
this.libraryInstance.on('change', (newData) => {
this.data = newData;
});
// 3. WildflowerJS state changes → update library
this.watch = {
data: () => this.libraryInstance.setData(this.data)
};
},
// 4. Clean up on destroy
destroy() {
if (this.libraryInstance) {
this.libraryInstance.destroy();
}
}
});
Libraries Known to Work Well
| Library | Purpose | Integration Notes |
|---|---|---|
| SortableJS | Drag-and-drop sorting | Works with both data-list and manual rendering. See Third-Party Integration. |
| Leaflet | Interactive maps | Call wildflower.scan() after popup opens to initialize components inside map popups. |
| Chart.js | Charts and graphs | Canvas-based. State changes update chart via chart.update(). |
| FullCalendar | Calendar UI | Use watchers to sync events between state and calendar instance. |
| Flatpickr | Date/time picker | Enhances a standard <input>. Works with data-model directly. |
| Tippy.js | Tooltips & popovers | Attaches to existing DOM elements. No conflicts with data bindings. |
| Quill / TinyMCE | Rich text editors | Initialize on a container element. Sync content via editor events. |
| Prism.js / Highlight.js | Code highlighting | Call after dynamic content loads. This documentation site uses Prism.js. |
Web Component Libraries
Web Component libraries like Web Awesome, Fluent UI, Nord Health, Shoelace, and IBM Carbon provide rich, pre-built UI widgets as custom HTML elements with Shadow DOM encapsulation.
Smart Defaults: Most Libraries Work Automatically
WildflowerJS auto-detects custom elements and their capabilities. For any element with a hyphen in its tag name, the framework automatically:
- Detects the property: if the element has a boolean
checkedproperty, it useschecked; otherwise it usesvalue - Listens for native events: listens for both
inputandchangeevents, which covers text inputs, selects, and booleans - Protects Shadow DOM: never sets
textContenton custom elements, preventing light DOM destruction
These smart defaults handle simple cases automatically. For production use, load the library's adapter pack, a single script tag that adds precise ready-timing (Lit's updateComplete) and explicit property mapping for every widget in the library.
| Library | Events | Adapter Needed? | Setup |
|---|---|---|---|
| Web Awesome 3.x | Native input / change |
Yes | Load library + adapter |
| Fluent UI v2 | Native input / change |
Yes | Load library + adapter |
| Nord Health | Native input / change |
Yes | Load library + adapter |
| Shoelace 2.x | Prefixed: sl-input / sl-change |
Yes | Load library + adapter |
| IBM Carbon v2 | Custom: cds-*-changed / cds-*-selected |
Yes | Load library + adapter |
checked vs value) and the async updateComplete lifecycle. Each adapter is a single script tag.
With Adapter (Web Awesome)
<!-- Load Web Awesome from CDN -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@aspect.me/webawesome@3/dist-cdn/styles/themes/default.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@aspect.me/webawesome@3/dist-cdn/webawesome.loader.js"></script>
<!-- Load WildflowerJS + adapter -->
<script src="wildflower.min.js"></script>
<script src="adapters/web-awesome.js"></script>
<!-- Use data-model as normal: -->
<div data-component="form-demo">
<wa-input label="Name" data-model="name"></wa-input>
<wa-select label="Role" data-model="role">
<wa-option value="dev">Developer</wa-option>
<wa-option value="design">Designer</wa-option>
</wa-select>
<wa-checkbox data-model="agreed">I agree</wa-checkbox>
<p>Hello, <span data-bind="name"></span>!</p>
</div>
With Adapter (Nord Health)
Nord Health is an enterprise design system with input, select, textarea, checkbox, toggle, and range components. Like Web Awesome, it uses an adapter pack for two-way binding.
With Adapter (Shoelace)
<!-- 1. Load the component library -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace/cdn/themes/light.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace/cdn/shoelace-autoloader.js"></script>
<!-- 2. Load WildflowerJS -->
<script src="wildflower.min.js"></script>
<!-- 3. Load the adapter pack -->
<script src="wildflower-adapters/shoelace.js"></script>
<!-- 4. Use Web Components with data-model, just like native inputs -->
<div data-component="contact-form">
<sl-input label="Name" data-model="name"></sl-input>
<sl-input label="Email" type="email" data-model="email"></sl-input>
<sl-textarea label="Message" data-model="message"></sl-textarea>
<sl-checkbox data-model="subscribe">Subscribe to newsletter</sl-checkbox>
<sl-button variant="primary" data-action="submit">Send</sl-button>
<p>Preview: <span data-bind="name"></span> (<span data-bind="email"></span>)</p>
</div>
wildflower.component('contact-form', {
state: {
name: '',
email: '',
message: '',
subscribe: false
},
submit() {
console.log('Form data:', {
name: this.name,
email: this.email,
message: this.message,
subscribe: this.subscribe
});
}
});
Registering Custom Adapters
For Web Components not covered by an existing adapter pack, register adapters manually:
// Register a single adapter
wildflower.registerAdapter('my-custom-input', {
prop: 'value', // The JS property to read/write
event: 'value-changed' // The event that fires on user interaction
});
// Now data-model works with <my-custom-input>
// <my-custom-input data-model="username"></my-custom-input>
The data-model-event Override
For one-off situations where you need a specific event name without registering a full adapter:
<!-- Override the event name directly on the element -->
<fancy-datepicker data-model="selectedDate" data-model-event="date-selected">
</fancy-datepicker>
Resolution order: data-model-event attribute > registered adapter > smart default (native input + change).
Adapter Packs
WildflowerJS ships adapter packs for popular Web Component libraries. Each adapter maps the library's property names, event names, and async lifecycle (e.g. Lit's updateComplete). Drop in a single <script> tag after the framework.
Some libraries also use non-standard event names, which the adapter handles:
| Library | Prefix | Why Adapter Needed | Adapter File | Components Covered |
|---|---|---|---|---|
| Shoelace 2.x | sl-* |
Uses prefixed events (sl-input, sl-change) |
adapters/shoelace.js |
9 (input, textarea, select, radio-group, checkbox, switch, range, rating, color-picker) |
| IBM Carbon v2 | cds-* |
Per-component custom events (cds-dropdown-selected, cds-checkbox-changed, etc.) |
adapters/carbon.js |
12 (text-input, textarea, password-input, search, number-input, select, dropdown, combo-box, checkbox, toggle, radio-button-group, slider) |
CDN Drop-in Usage
<!-- Shoelace (needs adapter, prefixed events) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.20.1/cdn/themes/dark.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.20.1/cdn/shoelace-autoloader.js"></script>
<script src="wildflower.min.js"></script>
<script src="adapters/shoelace.js"></script>
<!-- IBM Carbon (needs adapter, per-component custom events) -->
<script type="module" src="https://1.www.s81c.com/common/carbon/web-components/tag/v2/latest/text-input.min.js"></script>
<script type="module" src="https://1.www.s81c.com/common/carbon/web-components/tag/v2/latest/dropdown.min.js"></script>
<script src="wildflower.min.js"></script>
<script src="adapters/carbon.js"></script>
<!-- Web Awesome -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@aspect.me/webawesome@3/dist-cdn/styles/themes/default.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@aspect.me/webawesome@3/dist-cdn/webawesome.loader.js"></script>
<script src="wildflower.min.js"></script>
<script src="adapters/web-awesome.js"></script>
<!-- Fluent UI -->
<script type="module" src="https://cdn.jsdelivr.net/npm/@fluentui/web-components@2.6.1/dist/web-components.min.js"></script>
<script src="wildflower.min.js"></script>
<script src="adapters/fluent-ui.js"></script>
<!-- Nord Health -->
<link rel="stylesheet" href="https://nordcdn.net/ds/css/4.2.0/nord.min.css">
<link rel="stylesheet" href="https://nordcdn.net/ds/tokens/8.0.0/tokens.custom-properties.css">
<script type="module" src="https://nordcdn.net/ds/components/4.11.0/index.js"></script>
<script src="wildflower.min.js"></script>
<script src="adapters/nord.js"></script>
Manual Adapter Registration
If you encounter a Web Component not covered by an existing adapter pack, register an adapter manually:
// Register an adapter for a custom element
wildflower.registerAdapter('my-custom-input', {
prop: 'value', // JS property to read/write
event: 'value-changed' // Event that fires on user interaction
});
// WildflowerJS auto-detects 'value' vs 'checked' and listens for both events.
Choosing the Right Approach
Use this decision tree to pick the right integration tier for your project:
Zero JavaScript overhead, zero conflicts, zero configuration.
Use vanilla JS libraries. Initialize in
init(), sync with watchers.
See Third-Party JS Libraries for integration patterns.
Use Web Awesome, Fluent UI, Nord, Shoelace, or IBM Carbon. Each needs a one-line adapter script tag for two-way binding.
Mixing Approaches
These tiers are not mutually exclusive. A typical production app might use:
<!-- Tailwind/DaisyUI for layout and basic styling -->
<link href="https://cdn.jsdelivr.net/npm/daisyui@4/dist/full.min.css" rel="stylesheet">
<!-- Shoelace for rich form widgets -->
<script type="module" src="https://cdn.jsdelivr.net/.../shoelace-autoloader.js"></script>
<!-- Chart.js for data visualization -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<!-- WildflowerJS ties it all together -->
<script src="wildflower.min.js"></script>
<script src="wildflower-adapters/shoelace.js"></script>
DaisyUI handles your card layouts and button styles. Shoelace provides a polished date picker and color picker. Chart.js renders your dashboard graphs. WildflowerJS manages the reactive state that drives all of them.