---
title: Bottom Sheet Plugin
related:
  - title: Dialog Plugin
    path: dialog.md
  - title: Dialog
    path: ../vue-components/dialog.md
---
Bottom Sheets slide up from the bottom edge of the device screen, and display a set of options with the ability to confirm or cancel an action. Bottom Sheets can sometimes be used as an alternative to menus, however, they should not be used for navigation.

The Bottom Sheet always appears above any other components on the page, and must be dismissed in order to interact with the underlying content. When it is triggered, the rest of the page darkens to give more focus to the Bottom Sheet options.

Bottom Sheets can be displayed as a list or as a grid, with icons or with avatars. They can be used either as a component in your Vue file templates, or as a globally available method.

## BottomSheet API

### Methods

- `create(opts: object): object`
  Creates an ad-hoc Bottom Sheet; Same as calling $q.bottomSheet(...)
  Params:
    - `opts` (object, required)
      Bottom Sheet options
      Object shape:
        - `class` (string | any[] | object, optional)
          CSS Class name to apply to the Dialog's QCard
          Examples: `'my-class'`
        - `style` (string | any[] | object, optional)
          CSS style to apply to the Dialog's QCard
          Examples: `'border: 2px solid black'`
        - `title` (string, optional)
          Title
          Examples: `'Share'`
        - `message` (string, optional)
          Message
          Examples: `'Please select how to share'`
        - `actions` (any[], optional)
          Array of Objects, each Object defining an action
          Object shape:
            - `classes` (string | any[] | object, optional)
              CSS classes for this action
              Examples: `'my-class'`
            - `style` (string | any[] | object, optional)
              Style definitions to be attributed to this action element
              Examples: `{ padding: '2px' }`
            - `icon` (string, optional)
              Icon name following Quasar convention; Make sure you have the icon library installed unless you are using 'img:' prefix; If 'none' (String) is used as value then no icon is rendered (but screen real estate will still be used for it)
              Examples: `'map'`, `'ion-add'`, `'img:https://cdn.quasar.dev/logo-v2/svg/logo.svg'`, `'img:path/to/some_image.png'`
            - `img` (string, optional)
              Path to an image for this action
              Examples: `(public folder) 'img/something.png'`, `(relative path format) :src="require('./my_img.jpg')"`, `(URL) https://some-site.net/some-img.gif`
            - `avatar` (string, optional)
              Path to an avatar image for this action
              Examples: `(public folder) 'img/avatar.png'`, `(relative path format) :src="require('./my_img.jpg')"`, `(URL) https://some-site.net/some-img.gif`
            - `label` (string | number, optional)
              Action label
              Examples: `'Facebook'`
            - `...` (any, optional)
              Any other custom props
        - `grid` (boolean, optional)
          Display actions as a grid instead of as a list
        - `dark` (boolean, optional), default `null`
          Apply dark mode
        - `seamless` (boolean, optional)
          Put Bottom Sheet into seamless mode; Does not use a backdrop so user is able to interact with the rest of the page too
        - `persistent` (boolean, optional)
          User cannot dismiss Bottom Sheet if clicking outside of it or hitting ESC key; Also, an app route change won't dismiss it
  Returns: `object`
    Chainable Object
    Object shape:
      - `onOk` (Function, required)
        Receives a Function param to tell what to do when OK is pressed / option is selected
        Function signature: `(callbackFn: Function) => object`
        Params:
          - `callbackFn` (Function, required)
            Tell what to do
            Function signature: `(payload?: any) => void`
            Examples:
              - `() => console.log('OK!')`
              - `payload => Notify.create({ type: 'positive', message: `Successfully saved '${payload.book.name}' book!` })`
            Params:
              - `payload` (any, optional)
                The payload if called onDialogOK with the parameter or emitted one with the 'ok' event
                Examples:
                  - `'Quasar Framework'`
                  - `[1, 2, 6, 3]`
                  - `{ book: { id: 1, name: 'Lorem Ipsum' }, user: { name: 'Lorem J. Ipsum', role: 'admin' } }`
        Returns: `object`
          Chained Object
      - `onCancel` (Function, required)
        Receives a Function as param to tell what to do when Cancel is pressed / dialog is dismissed
        Function signature: `(callbackFn: Function) => object`
        Params:
          - `callbackFn` (Function, required)
            Tell what to do
            Function signature: `(reason?: string) => void`
            Examples: `() => console.log('Cancelled')`, `reason => { if (reason === 'cancel') { console.log('Cancel button was clicked') } }`
            Params:
              - `reason` (string, optional) *(added v2.28)*
                Why the dialog got dismissed: Cancel button, backdrop click, ESC key, or hidden through code (which includes an app route change); With a custom component, it mirrors the payload of the component's 'hide' event
                Accepts: `'cancel'`, `'backdrop'`, `'escape'`, `'programmatic'`
        Returns: `object`
          Chained Object
      - `onDismiss` (Function, required)
        Receives a Function param to tell what to do when the dialog is closed
        Function signature: `(callbackFn: Function) => object`
        Params:
          - `callbackFn` (Function, required)
            Tell what to do
            Function signature: `(payload?: any) => void`
            Params:
              - `payload` (any, optional) *(added v2.28)*
                When closed through OK, the same payload the onOk callback receives; Otherwise the dismissal reason ('cancel', 'backdrop', 'escape' or 'programmatic')
        Returns: `object`
          Chained Object
      - `hide` (Function, required)
        Hides the dialog when called
        Function signature: `() => object`
        Returns: `object`
          Chained Object
      - `update` (Function, required)
        Updates the initial properties (given as create() param) except for 'component'
        Function signature: `(opts: object) => object`
        Params:
          - `opts` (object, required)
            If using with 'component' prop then the props to update the current 'componentProps' (will be shallowly merged on top of the previous 'componentProps'); Otherwise the props to be shallowly merged with the previous create() param Object
        Returns: `object`
          Chained Object

### Vue Injection

Accessible via `$q.bottomSheet` (e.g., `this.$q.bottomSheet` in Options API or `useQuasar().bottomSheet` in Composition API).

## Installation

Add to `quasar.config.js`:

```js
framework: {
    plugins: [
      'BottomSheet'
    ]
}
```

## Usage

Example "Outside of a Vue file":

```js
import { BottomSheet } from 'quasar'
BottomSheet.create({ ... }) // returns Object

// inside of a Vue file
import { useQuasar } from 'quasar'
setup () {
  const $q = useQuasar()
  $q.bottomSheet({ ... }) // returns Object
}
```

> [!NOTE]
> When user hits the phone/tablet back button (only for Cordova apps), the Action Sheet will get closed automatically.
>
> Also, when on a desktop browser, hitting the `ESCAPE` key also closes the Action Sheet.

Starting with Quasar v2.28, the `onCancel` callback (and `onDismiss`, when no action was picked) receives the reason for the dismissal: `backdrop`, `escape` (the ESC key) or `programmatic` (hidden through code, which includes an app route change).

Example "List and Grid":

```vue
<template>
  <div class="q-gutter-sm">
    <q-btn
      no-caps
      push
      color="primary"
      label="List BottomSheet"
      @click="show()"
    />
    <q-btn
      no-caps
      push
      color="white"
      text-color="primary"
      label="Grid BottomSheet"
      @click="show(true)"
    />
  </div>
</template>

<script setup>
import { useQuasar } from 'quasar'

const $q = useQuasar()

function show(grid) {
  $q.bottomSheet({
    message: 'Bottom Sheet message',
    grid,
    actions: [
      {
        label: 'Drive',
        img: 'https://cdn.quasar.dev/img/logo_drive_128px.png',
        id: 'drive'
      },
      // ...
      {},
      {
        label: 'Share',
        icon: 'share',
        id: 'share'
      },
      {
        label: 'Upload',
        icon: 'cloud_upload',
        color: 'primary',
        id: 'upload'
      },
      {},
      {
        label: 'John',
        avatar: 'https://cdn.quasar.dev/img/boy-avatar.png',
        id: 'john'
      }
    ]
  })
    .onOk(action => {
      console.log('Action chosen:', action.id)
    })
    .onCancel(reason => {
      // reason (Quasar v2.28+) is 'backdrop',
      // 'escape' or 'programmatic'
      console.log('Dismissed:', reason)
    })
    .onDismiss(() => {
      console.log('I am triggered on both OK and Cancel')
    })
}
</script>
```

Example "Force dark mode":

```vue
<template>
  <div class="q-gutter-sm">
    <q-btn
      no-caps
      push
      color="primary"
      label="List BottomSheet"
      @click="show()"
    />
    <q-btn
      no-caps
      push
      color="white"
      text-color="primary"
      label="Grid BottomSheet"
      @click="show(true)"
    />
  </div>
</template>

<script setup>
import { useQuasar } from 'quasar'

const $q = useQuasar()

function show(grid) {
  $q.bottomSheet({
    dark: true,
    message: 'Bottom Sheet message',
    grid,
    actions: [
      {
        label: 'Drive',
        img: 'https://cdn.quasar.dev/img/logo_drive_128px.png',
        id: 'drive'
      },
      // ...
      {},
      {
        label: 'Share',
        icon: 'share',
        id: 'share'
      },
      {
        label: 'Upload',
        icon: 'cloud_upload',
        color: 'primary',
        id: 'upload'
      },
      {},
      {
        label: 'John',
        avatar: 'https://cdn.quasar.dev/img/boy-avatar.png',
        id: 'john'
      }
    ]
  })
    .onOk(action => {
      console.log('Action chosen:', action.id)
    })
    .onCancel(() => {
      console.log('Dismissed')
    })
    .onDismiss(() => {
      console.log('I am triggered on both OK and Cancel')
    })
}
</script>
```

> [!NOTE]
> For an exhaustive list of options, please check API section.
