Vue.js 3 runtime core library providing foundational APIs for building custom renderers and managing reactive component systems
—
Vue provides helper utilities for composition API usage including template refs, v-model integration, unique ID generation, and setup context access.
Create reactive references to template elements and component instances.
/**
* Creates a template ref for accessing DOM elements or component instances
* @param key - Template ref key (must match ref attribute in template)
* @returns Template ref object
*/
function useTemplateRef<T = any>(key: string): TemplateRef<T>;
interface TemplateRef<T = any> extends Ref<T> {
readonly value: T;
}Usage Examples:
import { defineComponent, useTemplateRef, onMounted } from "@vue/runtime-core";
const MyComponent = defineComponent({
setup() {
// Create template refs
const inputRef = useTemplateRef<HTMLInputElement>('input');
const childRef = useTemplateRef<ComponentInstance>('child');
onMounted(() => {
// Access DOM element
if (inputRef.value) {
inputRef.value.focus();
console.log('Input value:', inputRef.value.value);
}
// Access child component instance
if (childRef.value) {
// Call child component methods
childRef.value.someMethod();
}
});
return {
inputRef,
childRef
};
},
template: `
<div>
<input ref="input" type="text" />
<ChildComponent ref="child" />
</div>
`
});Create reactive references for v-model bindings with built-in getter/setter logic.
/**
* Creates a model ref for v-model integration
* @param props - Component props object
* @param name - Model property name
* @param options - Model configuration options
* @returns Model ref with getter/setter
*/
function useModel<T>(
props: Record<string, any>,
name: string,
options?: UseModelOptions
): ModelRef<T>;
interface UseModelOptions {
/**
* Default value when prop is undefined
*/
defaultValue?: any;
/**
* Whether the model should be deeply reactive
*/
deep?: boolean;
/**
* Transform function for incoming value
*/
get?(value: any): any;
/**
* Transform function for outgoing value
*/
set?(value: any): any;
}
interface ModelRef<T> extends Ref<T> {
readonly [ModelRefMarkerSymbol]: true;
}Usage Examples:
import { defineComponent, useModel } from "@vue/runtime-core";
// Basic v-model component
const CustomInput = defineComponent({
props: {
modelValue: String,
placeholder: String
},
emits: ['update:modelValue'],
setup(props, { emit }) {
// Create model ref that syncs with v-model
const model = useModel(props, 'modelValue');
return {
model
};
},
template: `
<input
v-model="model"
:placeholder="placeholder"
/>
`
});
// Multiple v-model support
const MultiModelComponent = defineComponent({
props: {
firstName: String,
lastName: String,
age: Number
},
emits: ['update:firstName', 'update:lastName', 'update:age'],
setup(props) {
const firstName = useModel(props, 'firstName');
const lastName = useModel(props, 'lastName');
const age = useModel(props, 'age', {
defaultValue: 0,
get: (value) => Number(value) || 0,
set: (value) => Math.max(0, Math.floor(value))
});
return {
firstName,
lastName,
age
};
}
});
// Usage:
// <MultiModelComponent
// v-model:firstName="user.firstName"
// v-model:lastName="user.lastName"
// v-model:age="user.age"
// />Generate unique IDs for accessibility and form associations.
/**
* Generates a unique ID for the current component instance
* @returns Unique string ID
*/
function useId(): string;Usage Examples:
import { defineComponent, useId } from "@vue/runtime-core";
const FormField = defineComponent({
props: {
label: String,
required: Boolean
},
setup(props) {
const id = useId();
return {
id,
inputId: `input-${id}`,
labelId: `label-${id}`,
errorId: `error-${id}`
};
},
template: `
<div>
<label :id="labelId" :for="inputId">
{{ label }}
<span v-if="required" aria-label="required">*</span>
</label>
<input
:id="inputId"
:aria-labelledby="labelId"
:aria-describedby="errorId"
:required="required"
/>
<div :id="errorId" class="error" aria-live="polite">
<!-- Error messages -->
</div>
</div>
`
});
// Multiple IDs in one component
const MultiIdComponent = defineComponent({
setup() {
const formId = useId();
const modalId = useId();
const tabsId = useId();
return {
formId: `form-${formId}`,
modalId: `modal-${modalId}`,
tabsId: `tabs-${tabsId}`
};
}
});Access component slots and attributes within setup function.
/**
* Gets setup context slots
* @returns Component slots object
*/
function useSlots(): Slots;
/**
* Gets setup context attrs (non-prop attributes)
* @returns Component attrs object
*/
function useAttrs(): Data;
interface Slots {
[name: string]: Slot | undefined;
default?: Slot;
}
type Slot<T = any> = (...args: any[]) => VNode[];
type Data = Record<string, unknown>;Usage Examples:
import { defineComponent, useSlots, useAttrs, h } from "@vue/runtime-core";
const WrapperComponent = defineComponent({
setup() {
const slots = useSlots();
const attrs = useAttrs();
// Check available slots
const hasHeader = !!slots.header;
const hasFooter = !!slots.footer;
const hasDefault = !!slots.default;
console.log('Available slots:', Object.keys(slots));
console.log('Component attrs:', attrs);
return () => h('div', {
class: 'wrapper',
...attrs // Forward all non-prop attributes
}, [
hasHeader && h('header', { class: 'header' }, slots.header!()),
hasDefault && h('main', { class: 'content' }, slots.default!()),
hasFooter && h('footer', { class: 'footer' }, slots.footer!())
]);
}
});
// Dynamic slot rendering
const DynamicSlots = defineComponent({
setup() {
const slots = useSlots();
return () => {
const slotElements = Object.entries(slots).map(([name, slot]) => {
if (slot) {
return h('div', {
key: name,
class: `slot-${name}`
}, slot());
}
return null;
}).filter(Boolean);
return h('div', { class: 'dynamic-slots' }, slotElements);
};
}
});
// Attrs manipulation
const AttrsComponent = defineComponent({
props: {
title: String
},
setup(props) {
const attrs = useAttrs();
// Filter out certain attributes
const filteredAttrs = computed(() => {
const { class: className, style, ...rest } = attrs;
return rest;
});
// Combine with custom attributes
const combinedAttrs = computed(() => ({
...filteredAttrs.value,
'data-component': 'attrs-component',
'aria-label': props.title || 'Custom component'
}));
return {
combinedAttrs
};
}
});// Composable using multiple helpers
function useFormField(name: string) {
const id = useId();
const attrs = useAttrs();
const fieldId = `field-${id}`;
const labelId = `label-${id}`;
const errorId = `error-${id}`;
// Extract validation attributes
const validationAttrs = computed(() => {
const { required, minlength, maxlength, pattern } = attrs;
return { required, minlength, maxlength, pattern };
});
return {
fieldId,
labelId,
errorId,
validationAttrs
};
}
// Ref forwarding pattern
const ForwardRefComponent = defineComponent({
setup(_, { expose }) {
const elementRef = useTemplateRef<HTMLElement>('element');
// Expose ref to parent
expose({
focus: () => elementRef.value?.focus(),
blur: () => elementRef.value?.blur(),
element: elementRef
});
return {
elementRef
};
}
});interface TemplateRef<T = any> extends Ref<T> {
/**
* Template ref marker for type discrimination
*/
readonly [TemplateRefSymbol]: true;
}
interface ModelRef<T = any> extends Ref<T> {
/**
* Model ref marker for type discrimination
*/
readonly [ModelRefMarkerSymbol]: true;
}
type UseModelOptions = {
defaultValue?: unknown;
deep?: boolean;
get?(value: unknown): unknown;
set?(value: unknown): unknown;
};
interface Slots {
[name: string]: Slot | undefined;
}
type Slot<T extends Record<string, any> = any> = (
props: T
) => VNode[];
type Data = Record<string, unknown>;Install with Tessl CLI
npx tessl i tessl/npm-vue--runtime-core