Components
ichigo.js components are real Custom Elements backed by the same reactivity system. Define one with defineComponent, pointing it at a <template> for its markup. Components use Light DOM, not Shadow DOM.
defineComponent
<!-- Component markup -->
<template id="my-list">
<ul v-if="items.length > 0">
<li v-for="item of items" :key="item.id">{{ item.name }}</li>
</ul>
<!-- Fallback projected from the parent -->
<slot></slot>
</template>
import { defineComponent } from '@mintjamsinc/ichigojs';
defineComponent('my-list', {
template: '#my-list', // CSS selector for the <template>
props: ['items'], // props received from the parent
data() {
// props are available via this and can be defaulted/transformed here
return { items: this.items ?? [] };
}
});
<!-- Usage -->
<my-list :items="searchResults">
<span slot="empty">No results.</span>
</my-list>
defineComponent(tagName, options) accepts the same options as createApp, plus two more:
template— CSS selector for the<template>that defines the markup (required)props— array of property names received from the parent via attribute/property binding
Props
- Declared via the
propsarray. Each declared prop becomes a property on the custom element, so the parent can bind to it withv-bind/:(e.g.:items="searchResults"). - Props are reactive from the start and are included in the component's data automatically. Values returned from
data()take precedence, so you can default or transform a prop (e.g.this.items ?? []).
defineComponent('user-badge', {
template: '#user-badge',
props: ['name', 'role'],
computed: {
label() { return `${this.name} (${this.role})`; }
}
});
Slots
Place a native <slot> inside the component <template> to project content from the parent. Named slots are supported.
<template id="modal-box">
<div class="modal">
<header><slot name="title">Title</slot></header>
<div class="body"><slot></slot></div>
</div>
</template>
<modal-box>
<span slot="title">Confirm</span>
<p>Are you sure you want to delete this?</p>
</modal-box>
Custom events ($emit)
Components (and applications) can dispatch custom events with $emit, available in both templates and methods. By default the event bubbles from the component's root element, so the parent can listen with @.
defineComponent('my-button', {
template: '#my-button',
// Optional: declare the events this component emits. Emitting an
// undeclared event logs a development warning (validation only; it
// never blocks dispatch). Omit emits to allow any event name.
emits: ['selected'],
methods: {
onClick() {
// $emit(name, detail?, options?)
this.$emit('selected', { id: 42 });
}
}
});
<!-- Parent listens; the payload is in event.detail -->
<my-button @selected="onSelected"></my-button>
methods: {
onSelected(event) {
console.log(event.detail.id); // 42
}
}
$emit(name, detail?, options?)
name— the event name (listened to as@nameon the parent)detail— the payload exposed asevent.detailoptions(VEmitOptions) —bubbles— whether the event bubbles (default:true)cancelable— whetherpreventDefault()has an effect (default:true);$emitreturnsfalsewhen a listener callspreventDefault()composed— whether the event crosses shadow DOM boundaries (default:false)target— the dispatch target (default: the application root element). Set todocument/windowfor a global event bus.
Refs on components
A ref placed on a component resolves to its host custom element, so you can call DOM methods like focus() or getBoundingClientRect(). See template refs in the Core guide.
<my-card ref="card"></my-card>
this.$refs.card; // the <my-card> element
Apps and components
Apps created with VDOM.createApp and components created with defineComponent share the same reactivity foundation. Options such as data / computed / methods / watch / emits / logLevel, and helpers like $markRaw / $nextTick / $emit / $refs, are common to both. The difference is that a component has template and props and is registered as a custom element.
Deprecated: v-component
⚠️ The
v-componentdirective andVComponentRegistryare deprecated and will be removed in a future release. UsedefineComponent(Custom Elements) for new code.
Next steps
- Syntax details → Directives reference
- Reactivity → Core guide