Skip to main content

CnTabbedFormDialog

A generic tabbed dialog for create/edit forms. Provides the standard dialog shell (NcDialog, tabs, notifications, action buttons) while the parent supplies tab content via slots.

Wraps: NcDialog, BTabs/BTab, NcButton, NcNoteCard, NcLoadingIcon, NcCheckboxRadioSwitch

Props

PropTypeDefaultDescription
tabsArray<{ id, title, icon?, disabled? }>requiredTab definitions. icon is a Vue component reference
itemObject|nullnullExisting item = edit mode; null = create mode
dialogTitleString''Custom title (overrides auto-generated)
entityNameString'Item'Used in auto-titles: "Create \{name\}" / "Edit \{name\}"
sizeString'large'NcDialog size
showCreateAnotherBooleanfalseShow "Create Another" checkbox in create mode
disableSaveBooleanfalseDisable primary button (parent controls validation)
disableSaveTooltipString''Tooltip shown on the save button when it is disabled — explains the blocked state to the user (also used as aria-label for accessibility).
successTextString''Custom success message
cancelLabelString'Cancel'Cancel button text
closeLabelString'Close'Close button text (result phase)
confirmLabelString''Primary button text (default: "Create"/"Save")
createAnotherLabelString'Create another'Checkbox label

Events

EventPayloadDescription
confirmnoneUser clicked Save/Create. Parent does API call, then calls setResult()
closenoneDialog should be closed
resetnone"Create another" success — parent should clear form data
update:activeTabnumberTab index changed (supports .sync)

Slots

SlotScoped PropsDescription
above-tabs{ loading }Optional content above the tab bar (e.g. metadata grid, detail cards)
tab-{id}{ loading }Content for each tab. The id comes from the tabs prop
below-tabs{ loading }Optional content below the tab bar (e.g. shared settings that apply across all tabs)
confirm-iconnoneCustom icon for the primary button (overrides default Plus/Save icons)
actions-left{ loading, isCreateMode, result }Extra content before Cancel button
actions-right{ loading, isCreateMode, result }Extra content after primary button

Public Methods

MethodParametersDescription
setResult{ success?, error? }Show result phase. Success auto-closes (2s) or resets in create-another mode
resetDialognoneClear result, reset loading, return to first tab

Usage

Basic (Edit Mode)

<CnTabbedFormDialog
ref="dialog"
:tabs="[
{ id: 'settings', title: 'Settings', icon: Cog },
{ id: 'quota', title: 'Quota', icon: Database },
{ id: 'security', title: 'Security', icon: Shield },
]"
:item="existingItem"
entity-name="Application"
:disable-save="!formData.name.trim()"
@confirm="saveApplication"
@close="closeModal">
<template #tab-settings="{ loading }">
<NcTextField :disabled="loading" label="Name *" :value.sync="formData.name" />
<NcTextArea :disabled="loading" label="Description" :value.sync="formData.description" />
</template>
<template #tab-quota="{ loading }">
<NcTextField :disabled="loading" label="Storage Quota (MB)" type="number" />
</template>
<template #tab-security="{ loading }">
<RbacTable :authorization="formData.authorization" />
</template>
</CnTabbedFormDialog>

Create Mode with "Create Another"

<CnTabbedFormDialog
ref="dialog"
:tabs="tabs"
:item="null"
entity-name="Organisation"
:show-create-another="true"
:disable-save="!formData.name.trim()"
@confirm="saveOrganisation"
@close="closeModal"
@reset="resetForm">
<template #tab-settings>
<!-- Form fields -->
</template>
</CnTabbedFormDialog>

Handling Save Result

async saveOrganisation() {
try {
const { response } = await store.save(this.formData)
if (response.ok) {
this.$refs.dialog.setResult({ success: true })
}
} catch (error) {
this.$refs.dialog.setResult({ error: error.message })
}
}