Skip to content

Modal ​

A popup window for showing messages or gathering user input.

Usage ​

Use a Button or any other component in the default slot of the Modal.

Then, use the #content slot to add the content displayed when the Modal is open.

vue
<template>
  <B24Modal>
    <B24Button label="Open" color="link" depth="dark" />

    <template #content>
      <Placeholder class="h-48 -m-4" />
    </template>
  </B24Modal>
</template>

You can also use the #header, #body and #footer slots to customize the Modal's content.

Title ​

Use the title prop to set the title of the Modal's header.

Details
vue
<script setup lang="ts">
export interface ExampleProps {
  title?: string
}

withDefaults(defineProps<ExampleProps>(), {
  title: 'Heads up!'
})
</script>

<template>
  <B24Modal
    :title="title"
  >
    <B24Button label="Open" color="link" depth="dark" />

    <template #body>
      <Placeholder class="h-48" />
    </template>
  </B24Modal>
</template>

Description ​

Use the description prop to set the description of the Modal's header.

Details
vue
<script setup lang="ts">
export interface ExampleProps {
  title?: string
  description?: string
}

withDefaults(defineProps<ExampleProps>(), {
  title: 'Heads up!',
  description: 'Let\'s signal the manager that the deal is not moving.'
})
</script>

<template>
  <B24Modal
    :title="title"
    :description="description"
  >
    <B24Button label="Open" color="link" depth="dark" />

    <template #body>
      <Placeholder class="h-48" />
    </template>
  </B24Modal>
</template>

Close ​

Use the close prop to customize or hide the close button (with false value) displayed in the Modal's header.

You can pass any property from the Button component to customize it.

TIP

The close button is not displayed if the #content slot is used as it's a part of the header.

Details
vue
<template>
  <B24Modal
    title="Modal with custom close button"
    description="The `close` prop inherits from the Button props."
    :close="{ color: 'danger', depth: 'dark', size: 'xs', rounded: true }"
    :b24ui="{ close: '-top-3 -end-3' }"
  >
    <B24Button label="Open" color="link" depth="dark" />

    <template #body>
      <Placeholder class="h-48" />
    </template>
  </B24Modal>
</template>

Close Icon ​

Use the close-icon prop to customize the close button @bitrix24/b24icons. Defaults to Cross30Icon.

Details
vue
<script setup lang="ts">
import EyeClosedIcon from '@bitrix24/b24icons-vue/button/EyeClosedIcon'
</script>

<template>
  <B24Modal
    title="Modal with custom close button"
    description="The `close-icon` prop use"
    :close-icon="EyeClosedIcon"
  >
    <B24Button label="Open" color="link" depth="dark" />

    <template #body>
      <Placeholder class="h-48" />
    </template>
  </B24Modal>
</template>

Overlay ​

Use the overlay prop to control whether the Modal has an overlay or not. Defaults to true.

Details
vue
<script setup lang="ts">
export interface ExampleProps {
  isOverlay?: boolean
}

withDefaults(defineProps<ExampleProps>(), {
  isOverlay: true
})
</script>

<template>
  <B24Modal
    :overlay="isOverlay"
    :title="`Modal ${isOverlay ? 'with' : 'without'} overlay`"
    description="The `overlay` prop use"
  >
    <B24Button label="Open" color="link" depth="dark" />

    <template #body>
      <Placeholder class="h-48" />
    </template>
  </B24Modal>
</template>

Transition ​

Use the transition prop to control whether the Modal is animated or not. Defaults to true.

Details
vue
<script setup lang="ts">
export interface ExampleProps {
  isTransition?: boolean
}

withDefaults(defineProps<ExampleProps>(), {
  isTransition: true
})
</script>

<template>
  <B24Modal
    :transition="isTransition"
    :title="`Modal ${isTransition ? 'with' : 'without'} transition`"
    description="The `transition` prop use"
  >
    <B24Button label="Open" color="link" depth="dark" />

    <template #body>
      <Placeholder class="h-48" />
    </template>
  </B24Modal>
</template>

Fullscreen ​

Use the fullscreen prop to make the Modal fullscreen.

Details
vue
<template>
  <B24Modal
    fullscreen
    title="Fullscreen Modal"
    description="The `fullscreen` prop use"
  >
    <B24Button label="Open" color="link" depth="dark" />

    <template #body>
      <Placeholder class="h-full" />
    </template>
  </B24Modal>
</template>

Examples ​

Control open state ​

You can control the open state by using the default-open prop or the v-model:open directive.

INFO

In this example, leveraging defineShortcuts, you can toggle the Modal by pressing O.

TIP

This allows you to move the trigger outside of the Modal or remove it entirely.

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

const open = ref(false)

defineShortcuts({
  o: () => open.value = !open.value
})
</script>

<template>
  <B24Modal
    v-model:open="open"
  >
    <B24Button label="Open" color="link" depth="dark" />

    <template #content>
      <Placeholder class="h-48" />
    </template>
  </B24Modal>
</template>

Prevent closing ​

Set the dismissible prop to false to prevent the Modal from being closed when clicking outside of it or pressing escape.

Details
vue
<template>
  <B24Modal
    :dismissible="false"
    title="Modal non-dismissible"
    description="`Esc` also doesn't work"
  >
    <B24Button label="Open" color="link" depth="dark" />

    <template #body>
      <Placeholder class="h-48" />
    </template>
  </B24Modal>
</template>

Programmatic usage ​

You can use the useModal composable to open a Modal programatically.

WARNING

Make sure to wrap your app with the App component which uses the ModalProvider component.

First, create a modal component that will be opened programatically:

vue
<script setup lang="ts">
const modal = useModal()

defineProps<{
  count: number
}>()

const emit = defineEmits(['success'])

function onSuccess() {
  emit('success')
}
</script>

<template>
  <B24Modal :title="`This modal was opened programmatically ${count} times`">
    <template #footer>
      <div class="flex gap-2">
        <B24Button
          color="success"
          label="Success"
          rounded
          size="sm"
          @click="onSuccess"
        />
        <B24Button
          rounded
          label="Close"
          color="link"
          depth="dark"
          size="sm"
          @click="modal.close()"
        />
      </div>
    </template>
  </B24Modal>
</template>

Then, use it in your app:

TIP

You can close the modal within the modal component by calling modal.close().

Details
vue
<script setup lang="ts">
import { ref } from 'vue'
import LazyModal from './LazyModal.vue'

const count = ref(0)

const toast = useToast()
const modal = useModal()

function open() {
  count.value++

  modal.open(LazyModal, {
    description: 'And you can even provide a description!',
    count: count.value,
    onSuccess() {
      toast.add({
        title: 'Success !',
        id: 'modal-success'
      })
    }
  })
}
</script>

<template>
  <B24Button
    label="Open"
    color="link"
    depth="dark"
    @click="open"
  />
</template>

Nested modals ​

You can nest modals within each other.

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

const first = ref(false)
const second = ref(false)
</script>

<template>
  <B24Modal
    v-model:open="first"
    title="First modal"
  >
    <B24Button label="Open" color="link" depth="dark" />

    <template #footer>
      <B24Button
        rounded
        label="Close"
        color="link"
        depth="dark"
        size="sm"
        @click="first = false"
      />
      <B24Modal
        v-model:open="second"
        title="Second modal"
      >
        <B24Button
          color="default"
          label="Open second"
          rounded
          size="sm"
        />

        <template #footer>
          <B24Button
            rounded
            label="Close"
            color="link"
            depth="dark"
            size="sm"
            @click="second = false"
          />
        </template>
      </B24Modal>
    </template>
  </B24Modal>
</template>

Use the #footer slot to add content after the Modal's body.

TIP

You can also close the dialog box using the B24ModalDialogClose component.

Details
vue
<template>
  <B24Modal
    title="Modal with footer"
    description="This is useful when you want a form in a Modal."
    :b24ui="{ footer: 'flex-row-reverse justify-start' }"
  >
    <B24Button label="Open" color="link" depth="dark" />

    <template #body>
      <Placeholder class="h-48" />
    </template>
    <template #footer>
      <B24ModalDialogClose>
        <B24Button rounded label="Send" color="primary" size="sm" />
      </B24ModalDialogClose>
      <B24ModalDialogClose>
        <B24Button rounded label="Cancel" color="link" depth="dark" size="sm" />
      </B24ModalDialogClose>
    </template>
  </B24Modal>
</template>

With body slot ​

Use the #body slot to add content.

Details
vue
<script setup lang="ts">
import FileUploadIcon from '@bitrix24/b24icons-vue/main/FileUploadIcon'
</script>

<template>
  <B24Modal
    title="File upload"
    description="Some demo from chat"
    :b24ui="{
      footer: 'border-t-0 mt-2.5 pt-0'
    }"
  >
    <B24Button label="Open" color="link" depth="dark" />

    <template #body>
      <div class="flex flex-col gap-4">
        <B24Separator />
        <div class="w-full flex flex-row flex-nowrap items-center justify-start gap-3">
          <div class="size-8xl rounded-xs border border-base-100 dark:border-white/20 flex flex-col items-center justify-center">
            <FileUploadIcon class="size-10 text-base-600" />
          </div>
          <div class="flex flex-col flex-nowrap gap-1">
            <div class="font-bold text-h5">
              start-ui.md
            </div>
            <div class="text-sm text-base-500 dark:text-base-600">
              650 bytes
            </div>
          </div>
        </div>
        <B24Separator />
        <div class="w-full">
          <B24Textarea autofocus placeholder="Add a comment" autoresize :rows="1" :maxrows="4" />
        </div>
      </div>
    </template>
    <template #footer>
      <B24ModalDialogClose>
        <B24Button rounded label="Send" color="primary" size="sm" />
      </B24ModalDialogClose>
      <B24ModalDialogClose>
        <B24Button rounded label="Cancel" color="link" depth="dark" size="sm" />
      </B24ModalDialogClose>
    </template>
  </B24Modal>
</template>

API ​

Props ​

Prop Default Type
titlestring
descriptionstring
contentOmit<DialogContentProps, "as" | "asChild" | "forceMount">
The content of the modal.
overlaytrueboolean
Render an overlay behind the modal.
transitiontrueboolean
Animate the modal when opening or closing.
fullscreenfalseboolean
When `true`, the modal will take up the full screen.
portaltrueboolean
Render the modal in a portal.
closetrueboolean | Partial<ButtonProps>
Display a close button to dismiss the modal. `{ size: 'xs', color: 'link' }`{lang="ts-type"}
closeIconicons.close(props: HTMLAttributes & VNodeProps & {}, ctx: Omit<{ attrs: Data; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<...>>(exposed?: Exposed) => void; }, "expose">): any
The icon displayed in the close button.
dismissibletrueboolean
When `false`, the modal will not close when clicking outside or pressing escape.
b24uiPartial<{ overlay: string; content: string; header: string; wrapper: string; body: string; footer: string; title: string; description: string; close: string; }>
openboolean
The controlled open state of the dialog. Can be binded as `v-model:open`.
defaultOpenboolean
The open state of the dialog when it is initially rendered. Use when you do not need to control its open state.
modaltrueboolean
The modality of the dialog When set to `true`, <br> interaction with outside elements will be disabled and only dialog content will be visible to screen readers.

Slots ​

Slot Type
default{ open: boolean; }
content{}
header{}
title{}
description{}
close{ b24ui: any; }
body{}
footer{}

Emits ​

Event Type

Released under the MIT License.