Todos los artículos
Componentes· Principiante

¿Cómo usar defineExpose?

Expón una API pequeña desde un modal y contrólala desde el padre con una referencia tipada.

LA

Luis Aldair Quispe Rios

2 min de lectura
¿Cómo usar defineExpose?

Objetivo y requisitos

Un componente con <script setup> mantiene su implementación privada. defineExpose permite publicar una API pequeña para que el padre la use a través de una referencia. Vamos a exponer open y close desde un modal. El ejemplo necesita Vue 3.5 o superior por useTemplateRef y un navegador compatible con el elemento HTML dialog.

MyModal.vue completo

Guárdalo en src/components/MyModal.vue. Usamos el diálogo nativo para obtener el comportamiento modal, el cierre con Escape y el manejo de foco del navegador.

<script setup lang="ts">
import { useTemplateRef } from 'vue'

const dialog = useTemplateRef<HTMLDialogElement>('dialog')

function open() {
  if (dialog.value && !dialog.value.open) dialog.value.showModal()
}

function close() {
  dialog.value?.close()
}

defineExpose({ open, close })
</script>

<template>
  <dialog ref="dialog" aria-labelledby="modal-title">
    <h2 id="modal-title">Un modal reutilizable</h2>
    <slot />
    <button type="button" autofocus @click="close">Cerrar</button>
  </dialog>
</template>

<style scoped>
dialog { max-width: 32rem; padding: 2rem; border: 0; border-radius: 1rem; }
dialog::backdrop { background: rgb(0 0 0 / 60%); }
</style>

La referencia a dialog permanece dentro del componente. El padre solo puede llamar a los dos métodos publicados. defineExpose es una macro y no necesita un import.

Uso completo desde App.vue

<script setup lang="ts">
import { useTemplateRef } from 'vue'
import MyModal from './components/MyModal.vue'

const modal = useTemplateRef<InstanceType<typeof MyModal>>('modal')
</script>

<template>
  <button type="button" @click="modal?.open()">Abrir modal</button>
  <MyModal ref="modal">
    <p>Este contenido llega desde el componente padre.</p>
  </MyModal>
</template>

Comprueba el resultado

Ejecuta npm run dev. Al pulsar «Abrir modal» aparece el diálogo y el foco se mueve dentro. Ciérralo con el botón y también con Escape; comprueba que puedes volver a abrirlo y que el foco regresa al botón de apertura. Recorre la interfaz con Tab. Ejecuta npm run build para comprobar los tipos y la compilación.

Cuándo usarlo y qué evitar

Este patrón es útil para operaciones imperativas como enfocar un input o abrir un diálogo. Para datos y estado compartido, suele ser más claro usar props, eventos o v-model. No expongas todo el estado interno solo porque puedas hacerlo: el contrato pequeño facilita cambiar la implementación después.

La referencia puede ser null antes de montar el hijo o cuando un v-if lo retira. Usa el acceso opcional y llama a defineExpose antes de un await. Si usas Vue anterior a 3.5, sustituye useTemplateRef por una referencia declarada con ref y conectada al mismo nombre de plantilla.

Consulta defineExpose y las referencias de plantilla en la documentación de Vue.

Sigue leyendo

Teleport en Vue 3: notificaciones con limpieza y claves estables

Teleport en Vue 3: notificaciones con limpieza y claves estables

Mueve notificaciones al body con Teleport, claves estables y limpieza de temporizadores.
defineModel() en Vue 3.4+: La evolución elegante del v-model en componentes

defineModel() en Vue 3.4+: La evolución elegante del v-model en componentes

Crea un input reutilizable con defineModel y aplica un modificador personalizado sin duplicar el modelo.
Cómo usar v-memo en Vue 3: dependencias y medición de rendimiento

Cómo usar v-memo en Vue 3: dependencias y medición de rendimiento

Optimiza una lista con v-memo, elige dependencias completas y compara el resultado antes de adoptarlo.