VVibeFlui

Action Config

Type: FluiKitActionConfig.

Properties

PropertyTypeRequiredDescription
keystringNoStable action key.
enabledbooleanNoEnables or disables the action.
labelstringNoVisible action label.
iconstringNoIconify icon name.
tooltipstringNoTooltip text.
ariaLabelstringNoAccessible label for icon actions.
display"button" | "icon"NoAction display mode.
iconOnlybooleanNoIcon-only display metadata.
variant"default" | "primary" | "secondary" | "danger" | "ghost"NoVisual variant.
confirmboolean | FluiKitConfirmConfigNoConfirmation config.
endpointFluiKitEndpointItemNoEndpoint override.
methodFluiKitHttpMethodNoHTTP method override.
handlerstringNoRegistry action handler key.
permissionstring | string[]NoRequired permission key(s).
visibleWhenFluiKitConditionNoConditional visibility.
disabledWhenFluiKitConditionNoConditional disabled state.
refreshOnSuccessbooleanNoRefreshes list after success when runtime flow applies.
classNamestringNoAction class name.

Resolution order

When an action runs, VibeFlui resolves what actually executes in this order:

  1. action.handler (registry action handler key on the action itself)
  2. schema.handlers[action.key] or schema.handlers[operation] (registry handler keyed by action/operation name)
  3. schema.provider (a named runtime provider registered through FluiKitProvider, or the built-in REST provider when provider.type is "rest" and no name is set)
  4. action.endpoint or schema.endpoint (REST-style endpoint config)

The first source that resolves wins. If both handler and endpoint are set on the same action, handler always runs and endpoint is ignored.

No-op behavior

If none of the sources above resolve — for example, an action references a handler key that was never registered, or has no endpoint/provider at all — VibeFlui does not throw an error. It displays success feedback assuming the operation completed, because VibeFlui only handles the FE/UI layer and is not responsible for backend results. The list still reloads and the form or dialog still closes as if a real request had succeeded.

Always wire a real handler, provider, or endpoint before treating an action as complete — an unwired action will look like it works in the UI even though no request was ever made.

Action groups

TS
actions: {
  create: { enabled: true, label: "Create user" },
  edit: { enabled: true },
  delete: { enabled: true, variant: "danger", confirm: true },
  row: [
    { key: "invite", label: "Invite", handler: "users.invite" }
  ],
  bulk: [
    { key: "export", label: "Export selected", handler: "users.exportSelected" }
  ],
  toolbar: [
    { key: "sync", label: "Sync", handler: "users.sync" }
  ]
}

Handler example

TS
const registry = createRegistry({
  actionHandlers: {
    "users.invite": async ({ row }) => ({
      status: true,
      code: 200,
      message: `Invite sent to ${String(row?.email ?? "user")}`
    })
  }
});