Dojo NG is being built in the open, one section at a time — follow along on Heptapod.

FRAMEWORKS

Vue

Vue 3 works with custom elements once it knows which tags they are. It binds properties with :name, listens for events with @name, and v-model works on the text inputs.

Install and register

npm install @dojo-ng/select @dojo-ng/chip @dojo-ng/text-input @dojo-ng/switch

Tell Vue's template compiler that dj-* tags are custom elements, so it does not try to resolve them as Vue components:

// vite.config.js
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

export default defineConfig({
  plugins: [
    vue({
      template: {
        compilerOptions: { isCustomElement: (tag) => tag.startsWith("dj-") },
      },
    }),
  ],
});

Then import the packages once, in your entry file. Each import registers its tag:

// main.js
import "@dojo-ng/select";
import "@dojo-ng/chip";
import "@dojo-ng/text-input";
import "@dojo-ng/switch";

import { createApp } from "vue";
import App from "./App.vue";

createApp(App).mount("#app");

If you use Vue without a build step, set the same option on the app instead:

// Without a build step, with Vue's in-browser template compiler
const app = createApp(App);
app.config.compilerOptions.isCustomElement = (tag) => tag.startsWith("dj-");
app.mount("#app");

An example

<script setup>
import { ref } from "vue";

const plans = [
  { value: "free", label: "Free" },
  { value: "pro", label: "Pro" },
];
const plan = ref("free");
const name = ref("");
const news = ref(false);
const tags = ref(["design", "docs"]);
</script>

<template>
  <dj-select
    label="Plan"
    :options.prop="plans"
    :value="plan"
    @change="plan = $event.target.value"
  ></dj-select>

  <dj-text-input label="Name" v-model="name"></dj-text-input>

  <dj-switch :checked="news" @change="news = $event.target.checked">
    Newsletter
  </dj-switch>

  <dj-chip
    v-for="tag in tags"
    :key="tag"
    closeable
    @dj-close="tags = tags.filter((t) => t !== tag)"
  >{{ tag }}</dj-chip>
</template>

Properties and attributes

  • A binding such as :value="plan" sets the property when the element has one, and otherwise sets an attribute.
  • Bind arrays and objects with the .prop modifier, as in :options.prop="plans". It always sets the property, even when the tag renders before its package is imported. Without .prop, an array bound too early becomes the attribute "[object Object]".
  • Plain attributes, such as label="Plan" and closeable, work as in HTML.

Events

  • Listen for a Dojo NG event by its exact name, with the dash: @dj-close, @dj-submit, @dj-select.
  • Standard events work as usual: @input, @change, and @click.
  • The event data is in $event.detail. Each component's API page lists its events.

v-model and forms

  • v-model works on the text inputs and the text area, because they have a value property and emit input.
  • v-model does not work on a checkbox, switch, or select. Bind :checked or :value, and update it in @change, as in the example.
  • The controls are form-associated, so a plain <form> with @submit.prevent and new FormData(form) also works. See Forms & validation.

TypeScript

Each package exports its element class, such as DjSelect from @dojo-ng/select. Use it to type a template ref, as in const select = ref<DjSelect | null>(null), so its properties and methods type-check.

Next: Angular Property and event bindings, ngModel, and reactive forms.