patternjavascriptvueTip
Vue 3 script setup macros: defineExpose, defineOptions, defineSlots
Viewed 0 times
defineOptions and defineSlots: Vue 3.3+
defineExposedefineOptionsdefineSlotsscript setuptemplate refcomponent name
Problem
Components using <script setup> are closed by default — template refs don't expose internal methods. Component names, inheritAttrs, and slot types require additional boilerplate.
Solution
Use the full set of script setup compiler macros:
<script setup lang="ts">
import { ref } from 'vue';
// defineExpose: make methods/state accessible via template ref
const inputRef = ref<HTMLInputElement | null>(null);
function focus() { inputRef.value?.focus(); }
defineExpose({ focus });
// defineOptions: set component name and other options (Vue 3.3+)
defineOptions({
name: 'BaseInput', // needed for KeepAlive :include
inheritAttrs: false, // control attribute fallthrough
});
// defineSlots: type your slots (Vue 3.3+)
defineSlots<{
default(props: { item: Item }): void;
header(): void;
}>();
</script>
<!-- Parent: access exposed method via ref -->
<template>
<BaseInput ref="inputRef" />
<button @click="inputRef?.focus()">Focus</button>
</template>
<script setup lang="ts">
import { ref } from 'vue';
// defineExpose: make methods/state accessible via template ref
const inputRef = ref<HTMLInputElement | null>(null);
function focus() { inputRef.value?.focus(); }
defineExpose({ focus });
// defineOptions: set component name and other options (Vue 3.3+)
defineOptions({
name: 'BaseInput', // needed for KeepAlive :include
inheritAttrs: false, // control attribute fallthrough
});
// defineSlots: type your slots (Vue 3.3+)
defineSlots<{
default(props: { item: Item }): void;
header(): void;
}>();
</script>
<!-- Parent: access exposed method via ref -->
<template>
<BaseInput ref="inputRef" />
<button @click="inputRef?.focus()">Focus</button>
</template>
Why
script setup components are closed by default because exposing everything would create fragile public APIs. defineExpose makes the intent explicit. defineOptions (3.3+) replaces the need for a separate <script> block just to set the component name.
Gotchas
- Without defineExpose, parent template refs to the component will be an empty proxy {}
- defineOptions replaces the need for a second <script> block for name/inheritAttrs
- useAttrs() and useSlots() composables access $attrs and $slots in script setup
- Accessing a ref to a component that uses KeepAlive — use defineExpose to expose state explicitly
Code Snippets
defineOptions with controlled attribute passthrough
<script setup>
defineOptions({ name: 'MyModal', inheritAttrs: false });
const { class: cls, ...rest } = useAttrs();
defineExpose({ open, close });
</script>Context
When working with Vue 3 script setup and needing to expose component methods or configure component options
Revisions (0)
No revisions yet.