All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m4s
- Cambiar selectedTab de ref(0) a ref('lotes') para usar string
- Agregar propiedad value explícita a cada tab item
- Crear documento nuxt-ui-tips.md con documentación de cambios
- Los valores deben ser strings según API de v4
4.2 KiB
4.2 KiB
Nuxt UI v4 - Tips y Cambios de API
Este documento contiene los cambios más comunes al migrar o trabajar con Nuxt UI v4, basado en la experiencia práctica del proyecto.
UModal - Componente Modal
Cambios de API en v4
1. v-model actualizado a v-model:open
❌ Incorrecto (API antigua):
<UModal v-model="showModal">
<!-- contenido -->
</UModal>
✅ Correcto (Nuxt UI v4):
<UModal v-model:open="showModal">
<!-- contenido -->
</UModal>
2. Slot #content requerido
En v4, el contenido debe ir dentro del slot #content.
❌ Incorrecto:
<UModal v-model:open="showModal">
<MiComponente />
</UModal>
✅ Correcto:
<UModal v-model:open="showModal">
<template #content>
<MiComponente />
</template>
</UModal>
3. Prop :ui para personalización
La prop :ui no tiene un slot width. Para personalizar el ancho, debes usar el slot content.
❌ Incorrecto:
<UModal
v-model:open="showModal"
:ui="{ width: 'max-w-4xl' }"
>
<!-- contenido -->
</UModal>
✅ Correcto:
<UModal
v-model:open="showModal"
:ui="{ content: 'w-[calc(100vw-2rem)] max-w-4xl rounded-lg shadow-lg ring ring-default' }"
>
<template #content>
<!-- contenido -->
</template>
</UModal>
Nota: Las clases del tema por defecto son:
w-[calc(100vw-2rem)]- ancho responsiverounded-lg- bordes redondeadosshadow-lg- sombraring ring-default- borde/anillo
Luego agregas tu clase de ancho máximo personalizado: max-w-3xl, max-w-4xl, etc.
Slots disponibles en UModal
Según la documentación oficial de Nuxt UI v4:
interface ModalSlots {
default(): any; // Elemento trigger (opcional)
content(): any; // Contenido completo del modal
header(): any; // Solo el header
title(): any; // Solo el título
description(): any; // Solo la descripción
actions(): any; // Acciones del header
close(): any; // Botón de cerrar
body(): any; // Solo el cuerpo
footer(): any; // Solo el footer
}
Props importantes
interface ModalProps {
open?: boolean; // Estado del modal (usar con v-model:open)
defaultOpen?: boolean; // Estado inicial
modal?: boolean; // Bloquea interacción fuera (default: true)
overlay?: boolean; // Mostrar overlay (default: true)
dismissible?: boolean; // Cerrar al hacer clic fuera (default: true)
transition?: boolean; // Animación (default: true)
fullscreen?: boolean; // Pantalla completa
scrollable?: boolean; // Contenido scrollable (v4.2+)
title?: string; // Título del modal
description?: string; // Descripción del modal
close?: boolean | Partial<ButtonProps>; // Customizar botón cerrar
}
Ejemplo completo
<template>
<!-- Modal básico con título y descripción -->
<UModal
v-model:open="showBasicModal"
title="Crear Nuevo Lote"
description="Complete el formulario para crear un lote"
>
<template #body>
<LoteForm @submit="handleSubmit" />
</template>
<template #footer>
<UButton @click="showBasicModal = false" variant="outline">
Cancelar
</UButton>
<UButton @click="handleSubmit">
Guardar
</UButton>
</template>
</UModal>
<!-- Modal con contenido personalizado y ancho custom -->
<UModal
v-model:open="showCustomModal"
:ui="{ content: 'w-[calc(100vw-2rem)] max-w-4xl rounded-lg shadow-lg ring ring-default' }"
>
<template #content>
<MiComponenteCustom />
</template>
</UModal>
</template>
<script setup lang="ts">
const showBasicModal = ref(false)
const showCustomModal = ref(false)
const handleSubmit = () => {
// lógica
showBasicModal.value = false
}
</script>
Resumen de Cambios Comunes
| Componente | Cambio | Desde | Hacia |
|---|---|---|---|
| UModal | v-model | v-model="show" |
v-model:open="show" |
| UModal | Contenido | Directo | <template #content> |
| UModal | Ancho custom | :ui="{ width: 'max-w-4xl' }" |
:ui="{ content: 'w-[calc(100vw-2rem)] max-w-4xl ...' }" |
Última actualización: 2025-11-21