Skip to content

FTxDialog

A flexible wrapper component for Quasar's QDialog with customizable header, footer, and content options. Supports both standalone mode (v-model) and store mode (useDialogStore).

Key Features

  • ✅ Standalone mode (v-model) or store mode (useDialogStore)
  • ✅ Customizable header with icon and subtitle
  • ✅ Scrollable content area with auto-height
  • ✅ Custom slots for complete control
  • ✅ All Quasar dialog props pass through automatically
  • ✅ No default padding (matches original behavior)

Props

PropTypeDefaultDescription
dialogStringnullDialog name (for store mode) - optional if using v-model
modelValueBooleanfalseDialog visibility (for standalone mode)
titleString''Dialog title shown in header
subtitleString''Subtitle shown below title
headerIconString''Icon shown in header before title
headerIconColorString'primary'Header icon color
headerIconSizeString'md'Header icon size
showHeaderBooleantrueShow header with title and close button
showCloseButtonBooleantrueShow close button in header
showFooterBooleantrueShow footer with action buttons
showResetButtonBooleantrueShow reset button in footer
showSaveButtonBooleantrueShow save button in footer
resetLabelString'Cancel'Reset button label
resetIconString''Reset button icon
resetLabelColorString'deep-purple-1'Reset button color
resetLabelTextColorString'primary'Reset button text color
resetLoadingBooleanfalseReset button loading state
saveLabelString'Save'Save button label
saveIconString''Save button icon
saveBtnColorString'primary'Save button color
saveTextColorString''Save button text color
saveDisabledBooleanfalseDisable save button
resetDisabledBooleanfalseDisable reset button
submittingBooleanfalseShow loading state on save button
sizeString''Dialog size class
cancelToCloseAllBooleantrueIf true, cancel button closes all dialogs (store mode only)
confirmBeforeCloseBooleanfalseIf true, emits reset event before closing
styleString | Object''Custom style for dialog card
contentClassString''Additional CSS classes for content
contentStyleString | Object''Inline styles for content
autoHeightBooleanfalseEnable auto-height layout (flex with scrollable content)
maxHeightString | NumbernullMax height for content area (when autoHeight is true)
contentPaddingString''Content padding class (e.g., 'q-pa-md') - empty by default
footerAlignString'between'Footer button alignment: 'left', 'right', 'between'
closeButtonAriaLabelString'Close dialog'Aria label for close button
saveButtonAriaLabelString'Save'Aria label for save button
resetButtonAriaLabelString'Cancel'Aria label for reset button

Quasar Dialog Props

All Quasar dialog props pass through automatically via $attrs:

  • persistent, maximized, position
  • transition-show, transition-hide
  • no-esc-dismiss, no-backdrop-dismiss, no-route-dismiss
  • auto-close
  • And all other Quasar QDialog props

Events

  • update:modelValue - Emitted when dialog visibility changes (standalone mode)
  • submit - Emitted when save button is clicked
  • reset - Emitted when reset button is clicked
  • hide - Emitted when dialog is hidden
  • show - Emitted when dialog is shown

Slots

  • default - Dialog content
  • header - Custom header (receives { close, title, icon })
  • footer - Custom footer (receives { submit, reset, submitting })
  • close-button - Custom close button (receives { close })

Usage Examples

Standalone Mode (v-model)

vue
<template>
  <div>
    <q-btn label="Open Dialog" @click="showDialog = true" />
    
    <FTxDialog
      v-model="showDialog"
      title="Example Dialog"
      subtitle="This is a subtitle"
      header-icon="info"
      :show-header="true"
      :show-footer="true"
      reset-label="Cancel"
      save-label="Save"
      persistent
      position="top"
      @submit="handleSubmit"
      @reset="handleReset"
    >
      <q-card-section>
        <q-input v-model="formData.name" label="Name" />
      </q-card-section>
    </FTxDialog>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { FTxDialog } from '@ftx/ui';

const showDialog = ref(false);
const formData = ref({ name: '' });

function handleSubmit() {
  console.log('Submitted:', formData.value);
  showDialog.value = false;
}

function handleReset() {
  formData.value = { name: '' };
  showDialog.value = false;
}
</script>

Store Mode (useDialogStore)

vue
<template>
  <div>
    <q-btn label="Open Dialog" @click="openDialog" />
    
    <FTxDialog
      dialog="example-dialog"
      title="Example Dialog"
      :show-header="true"
      :show-footer="true"
      reset-label="Cancel"
      save-label="Save"
      @submit="handleSubmit"
      @reset="handleReset"
    >
      <q-card-section>
        <q-input v-model="formData.name" label="Name" />
      </q-card-section>
    </FTxDialog>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { FTxDialog, useDialogStore } from '@ftx/ui';

const dialogStore = useDialogStore();
const formData = ref({ name: '' });

async function openDialog() {
  await dialogStore.updateDialog({
    name: 'example-dialog',
    value: true,
  });
}

function handleSubmit() {
  console.log('Submitted:', formData.value);
  dialogStore.closeDialog('example-dialog');
}

function handleReset() {
  formData.value = { name: '' };
  dialogStore.closeDialog('example-dialog');
}
</script>

Scrollable Content

vue
<FTxDialog
  v-model="showDialog"
  title="Long Content Dialog"
  auto-height
  max-height="500px"
  content-padding="q-pa-md"
>
  <q-card-section>
    <!-- Long scrollable content -->
  </q-card-section>
</FTxDialog>

Custom Header

vue
<FTxDialog v-model="showDialog" title="Custom Header">
  <template #header="{ close, title }">
    <q-card-section class="dialog-header bg-primary text-white">
      <div class="row items-center justify-between">
        <div class="text-h6">{{ title }}</div>
        <q-btn flat round dense icon="close" @click="close" />
      </div>
    </q-card-section>
  </template>
  
  <q-card-section>Content here</q-card-section>
</FTxDialog>
vue
<FTxDialog v-model="showDialog" title="Custom Footer">
  <q-card-section>Content here</q-card-section>
  
  <template #footer="{ submit, reset }">
    <q-card-section class="row justify-end q-gutter-sm q-pa-md">
      <q-btn label="Cancel" flat @click="reset" />
      <q-btn label="Save Draft" color="grey" @click="() => console.log('Draft')" />
      <q-btn label="Publish" color="primary" @click="submit" />
    </q-card-section>
  </template>
</FTxDialog>

Notes

  • Standalone mode: Use v-model for dialog state (doesn't require useDialogStore)
  • Store mode: Use dialog prop with useDialogStore for centralized dialog management
  • No default padding: Content has no padding by default (matches original behavior). Add content-padding="q-pa-md" if needed.
  • Quasar props: All Quasar dialog props pass through automatically - no need to define them explicitly

Released under the MIT License.