Skip to content

Modal Dialog Component ​

Dialogs opened from code through the modal service. They are kept on a stack, the call returns a promise, and a dialog can hold a @dynamicforms/vue-forms form.

Basic Usage ​

A message dialog, a yes/no confirmation, a form dialog with validation and sized dialogs, opened through the modal service. A <modal-view /> must be mounted once, in the app root - see Installation.

Modal Dialog Examples

The modal system provides several types of dialogs that can be triggered programmatically:

Message Dialog
Simple dialog with information message and a close button.
Confirmation Dialog
Dialog with Yes/No options for confirmation.
Form Dialog
Dialog with a form including validation.
Dialog Sizes
Dialogs with different sizes (small, medium, large, x-large); the inputs in the dialog change its title, icon, title color and size.

Features ​

  • One dialog at a time - a modal.* call made while a dialog is open hides that dialog without closing it and shows the new one. The hidden dialog is shown again when the new one closes.
  • Message dialogs - modal.message('Title', 'Text') shows a dialog with a single close action. The demo's message is Markdown (MdString) with a CSS class added through RenderableValue.
  • Confirmations - modal.yesNo('Title', 'Text') shows yes / no actions and resolves to whichever was clicked.
  • Form dialogs - a @dynamicforms/vue-forms Group passed as options.form is the dialog body. Its Action members (e.g. submit, cancel) are the dialog's buttons, and the promise resolves with the name of the one that was clicked; the dialog adds its own close only where none of them is drawn. A vue-forms Action and the @dynamicforms/vuetify-inputs Action are both drawn; the latter adds the responsive render options. Each Field is drawn as the component in field.extra.component, or as a <df-input> where it names none, with the field's label. A nested Group or List member is not drawn - see <modal-view>.
  • Error messages - the form dialog's email field has a pattern validator with the code invalid_email. The documentation app installs vuetify-inputs with an errorText that renders that code from a markdown message - see Translating errors.
  • Custom components - modal.custom('Title', component, componentProps) renders a component, or a component named in options.components or registered globally, as the dialog body.
  • Sizing - options.size is 'small', 'medium', 'large' or 'x-large'; each is fullscreen below its own breakpoint. 'default' sizes the dialog to its content.
  • Changing an open dialog - the sized dialogs' body holds an input for the title and selects for the icon, the title color and the size. The demo writes their values to the dialog's props.title, props.icon, props.color and props.size - see Changing an open dialog.

Changing an open dialog ​

The sized dialogs write the values of their inputs to the dialog's props, the DialogProps of the promise modal.message() returns:

ts
// Dialog sizes: the inputs in the dialog body write the title, the icon, the title color and the size to the open
// dialog's props
async function showSizedDialog(size: DialogSize) {
  const titleField = new Field({ value: 'Dialog Size Example', label: 'Dialog title' });
  const iconField = new Field({ value: 'mdi-resize', label: 'Icon' });
  const colorField = new Field({ value: 'none', label: 'Title color' });
  const sizeField = new Field({ value: size, label: 'Dialog size' });
  const icons = ['mdi-resize', 'mdi-star', 'mdi-heart', 'mdi-rocket', 'mdi-palette'];
  // 'none' sets no color: the title bar keeps its default
  const colors = ['none', 'primary', 'secondary', 'success', 'info', 'warning', 'error'];
  const colorOf = (name: string) => (name === 'none' ? undefined : name);

  const column = (cols: Record<string, number>, input: SimpleComponentDef): SimpleComponentDef => ({
    componentName: 'v-col',
    componentProps: cols,
    children: [input],
  });
  const dialog = modal.message(
    titleField.value,
    {
      componentName: 'v-row',
      children: [
        column({ cols: 12, sm: 8 }, { componentName: 'df-input', componentProps: { control: titleField } }),
        column(
          { cols: 12, sm: 4 },
          {
            componentName: 'df-select',
            componentProps: {
              control: iconField,
              choices: icons.map((icon) => ({ id: icon, text: icon.slice(4), icon })),
              allowNull: false,
            },
          },
        ),
        column(
          { cols: 12, sm: 6 },
          {
            componentName: 'df-select',
            componentProps: {
              control: colorField,
              choices: colors.map((color) => ({ id: color, text: color })),
              allowNull: false,
            },
          },
        ),
        column(
          { cols: 12, sm: 6 },
          {
            componentName: 'df-select',
            componentProps: {
              control: sizeField,
              choices: dialogSizes.map((name) => ({ id: name, text: name })),
              allowNull: false,
            },
          },
        ),
      ],
    },
    { icon: iconField.value, color: colorOf(colorField.value), size },
  );

  const stop = watch(
    () => [titleField.value, iconField.value, colorField.value, sizeField.value] as const,
    ([title, icon, color, dialogSize]) => {
      dialog.props.title = title;
      dialog.props.icon = icon;
      dialog.props.color = colorOf(color);
      dialog.props.size = dialogSize;
    },
  );

  dialogResult.value = await dialog;
  stop();
}

Full method signatures, CloseablePromise, ModalOptions, and DialogSize are documented in the modal service API reference.

See also ​

  • Template Dialog - a dialog declared in a template with <df-modal>.
  • API Reference - the props, methods and options of the modal service, <df-modal>, <modal-view> and DialogSize.

Released under the MIT License.