GrPromptDialog

  • core
  • overlays
  • API · 41 props
  • ⌨ keys

Requests a short text input from the user in a dialog.

import { GrPromptDialog } from '@feugene/granularity/components/GrPromptDialog'

Overview

When to take it

  • a single value is needed — the name of a folder, the reason for a refusal, a comment on a return: setting up a screen for the sake of one field is expensive;
  • the value is checked — rules and required work before the confirmation, and fieldError shows the server’s refusal;
  • the text is long — multiline with autosize turns the field into a text area;
  • the call comes from code — useDialogService().prompt() returns a Promise with the value.

When to take something else

NeedTake
Ask for consent rather than for a valueGrConfirmDialog
There are several fieldsGrDialog + GrForm
The field lives on the screen itselfGrFormField + GrInput
Choose from ready optionsGrDialog + GrSelect

Playground controls come from the API, not from hand

Stage

The window opens above the page with the props set on the right.

0 changed· state is in the URL

Examples 3 each with a live demo and its code

  • Renaming a report from its row

    v-model:value puts the current name in the field before the window opens — a rename almost always starts from it — and v-model holds the window. confirm brings the new value, not just the fact that the user agreed.

    Revenue by planUpdated Today
    Churned accounts Q3Updated Yesterday
    Overdue invoicesUpdated 2 days ago
  • A reason for a return

    A reason does not fit one line: multiline turns the field into a textarea, autosize grows it with the answer, and maxlength with show-count names the limit before it is hit — a scrollbar inside three rows would hide what has been written.

    Order #4820 · Wool cardigan, navy, LDelivered on 2 October · returnable until 30 OctoberDelivered
  • A project name the server has to accept

    rules check the form of the name in the window, and field-error brings the server’s refusal under the field. With close-on-confirm="false" the window closes only when the project exists; confirm-loading and persistent keep it in place while the server answers. Try «q4-campaign».

    Projects · 2
    website-relaunchbilling-migration

API generated from the package · cannot drift

Props

PropTypedefaultDescription
titlestring | undefinedundefinedThe heading of the window, which is also its accessible name. Unset — taken from the locale.
requiredboolean | undefinedtrueAn empty value cannot be confirmed; the error shows after the first blur of the field or an attempt to confirm. `true` by default.
size"sm" | "md" | "lg" | "xl" | "full" | undefinedundefinedThe width of the window on the `GrDialog` scale: from `sm` to `xl`, `full` — the whole screen. `md` by default.
placeholderstring | undefinedundefinedHint in an empty field.
namestring | undefinedundefinedThe name of the field. In the set not for company’s sake: password managers rely on it too, and for some of them saving a value without a name simply does not work.
descriptionstring | undefinedundefinedAn explanation above the field. The `default` slot replaces it.
labelstring | undefinedundefinedThe label of the field, which is also its accessible name. Unset — taken from the locale.
closeOnBackdropboolean | undefinedtrueClose on a click on the backdrop. `true` by default; with `persistent` it is switched off while a confirmation or a check of the `rules` is in progress.
closeOnEscboolean | undefinedtrueClose on Esc. `true` by default; with `persistent` it is switched off while a confirmation or a check of the `rules` is in progress.
showHeaderboolean | undefinedtrueShow the header with the heading and the close button. `true` by default.
showCloseButtonboolean | undefinedtrueThe close button in the header. `true` by default; it stays with `persistent` too.
headerConfigGrDialogSectionConfig | undefinedundefinedThe paddings and the line of the header: `paddingX`, `paddingY`, `bordered`.
footerConfigGrDialogSectionConfig | undefinedundefinedThe paddings and the line of the footer with the buttons.
bodyConfigGrDialogSectionConfig | undefinedundefinedThe paddings of the window body. `bordered` does not apply to the body.

Slots

SlotTypeDescription
defaultanyThe content of the dialog instead of the text from the `description` prop.
error{ error: ResponseErrorInfo | null; }A breakdown of the error instead of the built-in banner.
footeranyThe buttons of the dialog instead of the "cancel and confirm" pair.

Events

EventSignatureDescription
update:modelValue(event: "update:modelValue", value: boolean): void—
confirm(event: "confirm", value: string): void—
cancel(event: "cancel"): void—
update:value(event: "update:value", value: string): void—

Types

Every exported type of the subpath, grouped by the file it lives in. Names, generics and bodies come from the package’s declaration files and cannot drift.

Import
import type { GrPromptDialogProps, GrPromptDialogEmits } from '@feugene/granularity/components/GrPromptDialog'

Filedist/types/components/GrPromptDialog/GrPromptDialog.vue.d.ts

GrPromptDialogPropsinterface
interface GrPromptDialogProps {
    modelValue: boolean;
    value: string;
    title?: string;
    description?: string;
    label?: string;
    placeholder?: string;
    closeOnBackdrop?: boolean;
    closeOnEsc?: boolean;
    showHeader?: boolean;
    showCloseButton?: boolean;
    size?: GrDialogSize;
    headerConfig?: GrDialogSectionConfig;
    footerConfig?: GrDialogSectionConfig;
    bodyConfig?: GrDialogSectionConfig;
    closeLabel?: string;
    buttonSize?: GrButtonSize;
    confirmText?: string;
    cancelText?: string;
    cancelVariant?: GrButtonVariant;
    requiredErrorText?: string;
    confirmVariant?: GrButtonVariant;
    confirmTone?: GrButtonTone;
    required?: boolean;
    inputType?: GrInputType;
    inputmode?: InputHTMLAttributes['inputmode'];
    maxlength?: number;
    showCount?: boolean;
    autocomplete?: string;
    name?: string;
    autocapitalize?: 'off' | 'none' | 'on' | 'sentences' | 'words' | 'characters';
    spellcheck?: boolean;
    multiline?: boolean;
    rows?: number;
    autosize?: boolean;
    rules?: GrFormRule | GrFormRule[];
    error?: ResponseErrorInfo | null;
    fieldError?: string | null;
    confirmLoading?: boolean;
    confirmDisabled?: boolean;
    closeOnConfirm?: boolean;
    persistent?: boolean;
}
GrPromptDialogEmitsinterface
interface GrPromptDialogEmits {
    (e: 'update:modelValue', value: boolean): void;
    (e: 'update:value', value: string): void;
    (e: 'confirm', value: string): void;
    (e: 'cancel'): void;
}

Filedist/types/components/GrPromptDialog/config.d.ts

grPromptDialogConfigconst
const grPromptDialogConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrPromptDialog">;

Accessibility

Keys

EscTab / Shift+Tab

Usage from the library prose

The field

multiline switches GrInput to GrTextarea (rows, autosize) — the reason for a refusal or a comment must not be assembled through a slot. For a single-line field there are inputType (email, password, number, …) and inputmode. maxlength with showCount draws a counter; it is already linked to the field through aria-describedby.

The field is obliged to introduce itself to the browser

autocomplete, name, autocapitalize and spellcheck reach the field in both branches — the single-line and the multiline one. The default of all of them is the absence of the attribute: the window makes nothing up.

ts
dialog.prompt('Confirm the password', {
  inputType: 'password',
  autocomplete: 'current-password',
  name: 'password',
})

Without them a password manager does not recognise the field: 1Password, Safari and Chrome look at autocomplete and at the name of the field, and the confirmation of a password has to be typed by hand on every action.

autocomplete is not derived from inputType. One and the same password has three different correct values — current-password, new-password, one-time-code — and the window does not know which of them is right: it is used to ask for the old password, the new one and a one-time code alike. A guess here would be a lie.

autocapitalize and spellcheck are the pair to autocomplete="off" for secrets that are typed by hand. A 2FA backup code is compared byte for byte and is generated in mixed case: without autocapitalize="off" a mobile keyboard raises the first letter.

dialog.prompt has the same four fields — a divergence between the declarative and the imperative paths is guarded by the GrDialogService/__tests__/promptSurface.test.ts gate.

The field is not given an id: GrFormField generates it, and the field reads it from the context. A literal id used to break exactly what it was written for — two open dialogs (an ordinary one and one through the service) gave a duplicate DOM id, and <label for> led to someone else’s input.

Checking the value

required (true by default) is a quick synchronous “not empty” check. It blocks the button and does not go into the asynchronous engine.

Everything else is the rules prop with the same rules as in GrForm: type, min/max/len, pattern, a validator of your own, an asynchronous one included. There is no third special case of validation in the package — it is the same runFieldRules, and the messages are resolved by the same createGrFormMessageResolver (both are public).

vue
<GrPromptDialog
  v-model="open"
  v-model:value="email"
  :rules="{ type: 'email', message: 'A work address is required' }"
/>

The rules are run on blur (after the first touch) and on the confirmation. While a check is running, the button shows loading; the answer of a stale run is discarded — an asynchronous rule may come back after the value has already changed.

An error arrives from the outside as well: fieldError (the server-side validation of the field) is stronger than the built-in checks, and error draws a general banner in the body of the window.

The weight of cancel

Cancel is outline, as in GrConfirmDialog; cancelVariant changes it and is configured in GrConfigProvider together with the confirmation.

The focus and the keyboard

On opening, the focus goes into the field rather than onto the panel of the window: the dialog exists precisely for the sake of the input. That is done on the side of the content rather than with the initialFocus prop of GrModal — the element is born inside the subtree of the dialog, and returning it upwards through a prop closes the render into a loop.

Enter in a single-line field confirms. In the multiline mode Enter remains a line break, and the confirmation is done with the button.