The BModal component is a molecule that provides a complete modal dialog with optional form integration, customizable primary/secondary buttons, and flexible content slots.
state
Record<string, any> | null
default:"null"
The state object for form management. When provided, enables form mode.
schema
Record<string, any> | null
default:"null"
The schema for form validation (e.g., Zod, Yup)
The title displayed at the top of the modal
The description text shown below the title
Simple text content when you don’t need the slot with complex markup
Text label for the primary action button
primaryButtonColor
SemanticColors
default:"primary"
Color variant for the primary button
Text label for the secondary action button
Whether to display the modal footer with action buttons
Whether the primary button should be disabled
Whether buttons should be displayed as full-width blocks
Additional CSS classes for the button container
Additional CSS classes for the modal dialog
Controls the open/closed state of the modal
Reference to the form element (when using form mode)
Emitted when the primary button is clicked
on-click-secondary-button
Emitted when the secondary button is clicked. Automatically closes the modal.
Emitted when the form is submitted (only in form mode)
Custom header content (replaces title and description)
Main body content (used when text prop is not provided)
Custom footer content (replaces default action buttons)
Basic Modal
<template>
<div>
<UButton @click="isOpen = true">Open Modal</UButton>
<BModal
v-model="isOpen"
title="Confirm Action"
description="Are you sure you want to continue?"
text="This action cannot be undone."
@on-click-primary-button="handleConfirm"
/>
</div>
</template>
<script setup>
const isOpen = ref(false)
function handleConfirm() {
console.log('Confirmed')
isOpen.value = false
}
</script>
Modal with Form
<template>
<BModal
v-model="isOpen"
v-model:formRef="formRef"
title="Edit Profile"
:state="formState"
:schema="formSchema"
primary-button-text="Save Changes"
@on-submit="handleSubmit"
>
<UFormField label="Name" name="name">
<UInput v-model="formState.name" />
</UFormField>
<UFormField label="Email" name="email">
<UInput v-model="formState.email" type="email" />
</UFormField>
</BModal>
</template>
<script setup>
import { z } from 'zod'
const isOpen = ref(false)
const formRef = ref(null)
const formState = reactive({
name: '',
email: ''
})
const formSchema = z.object({
name: z.string().min(2),
email: z.string().email()
})
function handleSubmit() {
console.log('Form submitted', formState)
isOpen.value = false
}
</script>
<template>
<BModal
v-model="isOpen"
title="Custom Actions"
>
<p>Modal content here</p>
<template #footer>
<div class="flex justify-between w-full">
<UButton variant="ghost" @click="handleOption1">Option 1</UButton>
<UButton variant="ghost" @click="handleOption2">Option 2</UButton>
<UButton color="primary" @click="handleSave">Save</UButton>
</div>
</template>
</BModal>
</template>
<template>
<BModal
v-model="isOpen"
title="Information"
:has-footer="false"
>
<p>This modal has no footer buttons.</p>
</BModal>
</template>
Full-Width Buttons
<template>
<BModal
v-model="isOpen"
title="Confirm Delete"
text="This will permanently delete the item."
primary-button-text="Delete"
primary-button-color="error"
has-buttons-block
@on-click-primary-button="handleDelete"
/>
</template>
Disabled Primary Button
<template>
<BModal
v-model="isOpen"
title="Submit Form"
:is-primary-button-disabled="!formValid"
@on-click-primary-button="handleSubmit"
>
<p>Fill out the form to enable submission</p>
</BModal>
</template>
<script setup>
const formValid = ref(false)
</script>
Form Mode
When state prop is provided, the modal body is wrapped in a UForm component:
const formProps = computed(() => {
return props.state ? { ref: 'formRef', state: props.state, schema: props.schema } : {}
})
This enables:
- Form validation
- Submit event handling
- Form ref access via
v-model:formRef
The default footer uses the DActionButtons component with:
- Secondary button on the left (closes modal automatically)
- Primary button on the right
- Configurable colors, text, and disabled states
Source: /home/daytona/workspace/source/app/components/b/modal/b-modal.vue:152