-
Notifications
You must be signed in to change notification settings - Fork 0
Vue integration
Use the official Custom Elements directly from Vue SFCs. You do not need a separate Vue component implementation. This guide assumes an existing Vue 3 + Vite JavaScript app; Quick start covers installing the pinned release archive.
Merge this setting into your existing vite.config.js, keeping unrelated plugins and configuration:
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue({
template: { compilerOptions: {
isCustomElement: tag => tag.startsWith('j3w1-'),
} },
})],
});The setting belongs in the SFC compiler configuration. Adding it only to a runtime app instance does not configure already compiled SFCs.
Use this as src/App.vue in a small example app. It adapts the maintained text-field and button markup, adds an application-owned status select, and uses the supported enhancement so the select opens in j3w1 colors. The save action only displays local form data.
<script setup>
import { onBeforeUnmount, onMounted, ref } from 'vue';
import '@j3w1/ui/tokens.css';
import '@j3w1/ui/styles/text-field.css';
import '@j3w1/ui/styles/button.css';
import '@j3w1/ui/styles/controls.css';
import '@j3w1/ui/register/text-field';
import '@j3w1/ui/register/button';
import { enhanceControls } from '@j3w1/ui/enhance/choice';
const root = ref(null);
const displayName = ref('Atlas');
const status = ref('ready');
const saved = ref('');
let controls;
onMounted(() => { controls = enhanceControls(root.value); });
onBeforeUnmount(() => controls?.destroy());
function save(event) {
const data = new FormData(event.currentTarget);
saved.value = JSON.stringify(Object.fromEntries(data), null, 2);
}
function reset() {
displayName.value = 'Atlas';
status.value = 'ready';
saved.value = '';
}
</script>
<template>
<main ref="root" class="settings-example">
<h1>Project settings</h1>
<p>Local example; no data is sent to a server.</p>
<form @submit.prevent="save" @reset.prevent="reset">
<j3w1-text-field id="settings-name">
<div class="text-field">
<label class="text-field-label" for="settings-name-input">
Project name
<span class="text-field-required" aria-hidden="true">*</span>
<span class="text-field-required sr-only"> required</span>
</label>
<div class="text-field-root">
<input id="settings-name-input" class="text-field-input"
v-model="displayName" name="projectName" type="text" required
aria-describedby="settings-name-help settings-name-message">
<span class="text-field-loading" aria-hidden="true">⋯</span>
</div>
<p id="settings-name-help" class="text-field-help">Shown in your workspace.</p>
<p id="settings-name-message" class="text-field-message">Enter a project name.</p>
</div>
</j3w1-text-field>
<label for="settings-status">Status</label>
<select id="settings-status" v-model="status" name="status">
<option value="ready">Ready</option>
<option value="review">Review</option>
</select>
<j3w1-button id="settings-save">
<button class="button" type="submit">
<span class="button-loading" aria-hidden="true">⋯</span>
<span class="button-label">Save settings</span>
</button>
</j3w1-button>
<button type="reset">Reset example</button>
</form>
<pre aria-live="polite">{{ saved }}</pre>
</main>
</template>
<style>
body { margin: 0; background: var(--color-surface-canvas); }
.settings-example { max-width: 42rem; margin-inline: auto; padding: var(--space-16); }
.settings-example form { display: grid; gap: var(--space-12); }
.settings-example h1 { color: var(--color-text-prose); }
.settings-example pre { white-space: pre-wrap; overflow-wrap: anywhere; }
</style>Your usual Vue browser entry still mounts App:
import { createApp } from 'vue';
import App from './App.vue';
createApp(App).mount('#app');The wrapper does not implement Vue's modelValue convention. In this example, Vue owns the native input/select values. The reset handler updates that Vue state explicitly; it is not an example of submitting data to a backend.
| Need | Vue pattern |
|---|---|
| Native input value |
v-model on the native input/select |
| Object/array custom-element property |
:data.prop="series", using the component's declared data shape |
| Documented custom event |
@j3w1-change="onChange"; read event.detail
|
| Imperative API | Element ref, after mount, then the documented method |
| Replaced native child structure | After nextTick(), call the component's refresh()
|
| Existing raw controls | Enhance an explicit root after mount; destroy on unmount |
Do not assume every component emits the same event or accepts data. Read its generated API first. chart.data, for example, is an array of { label, value } with finite non-negative values and a documented row limit.
Use stable keys when Vue renders lists. Avoid giving both Vue and a component ownership of reordering the same children. Do not let a second enhancement root independently manage the same controls.
Test required validation, actual FormData, reset, dynamic values/options, unmount/remount and narrow layout. For a dialog test Escape and focus return; for choices test the visible themed menu with mouse and keyboard. Keep unique IDs across repeated instances.
The full Vue demo shows larger compositions. Its source is a package consumer, not a backend template. See Portal and demo for its boundaries.
Source: official consumption guide.
Wiki home · Agent workflow · Portal · Vue demo · v1.1.0 release
This handbook explains consumption of v1.1.0. The pinned repository's tokens, specification, implementation contracts and evidence remain authoritative. The live site may advance; keep your application's pin explicit. Preserve the material's license notices.