Skip to content
AI & Agents
Skill

/frappe-impl-ui-components

Use when building custom dialogs, extending List View, creating Page controllers, or adding Kanban/Calendar views and realtime updates. Prevents UI freezes from synchronous calls, broken dialogs from wrong field definitions, and missed socket events. Covers frappe.ui.Dialog,

From plugin
frappe-claude-skill-package
20061 skills

Claude Code

$ npx -y skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-impl-ui-components --agent claude-code

SKILL.md

frappe-impl-ui-components.SKILL.md
name: frappe-impl-ui-components
description: >
  Use when building custom dialogs, extending List View, creating Page controllers, or adding Kanban/Calendar views and realtime updates.
  Prevents UI freezes from synchronous calls, broken dialogs from wrong field definitions, and missed socket events.
  Covers frappe.ui.Dialog, frappe.ui.form.MultiSelectDialog, List View customization, frappe.pages, Kanban Board, Calendar View, frappe.realtime, socket.io publish/subscribe.
  Keywords: Dialog, List View, Page, Kanban, Calendar, realtime, socket.io, frappe.ui, MultiSelectDialog, publish_realtime, popup dialog, custom dialog, list view customize, realtime update, live data, kanban setup..
license: MIT
compatibility: "Claude Code, Claude.ai Projects, Claude API. Frappe v14-v16."
metadata:
  author: OpenAEC-Foundation
  version: "2.0"

Frappe UI Components & Realtime — Implementation Workflows

Step-by-step workflows for building client-side UI. For form scripting see `frappe-impl-clientscripts`. For server-side API see `frappe-syntax-serverscripts`.

**Version**: v14/v15/v16 | **Note**: v15+ uses Bootstrap 5; Dialog API is stable across all versions.

Quick Decision: Which UI Component?

WHAT do you need?
├── Prompt user for input         → frappe.prompt (simple) or frappe.ui.Dialog (complex)
├── Show a message/alert          → frappe.msgprint / frappe.show_alert / frappe.throw
├── Confirm an action             → frappe.confirm
├── Multi-field data entry popup  → frappe.ui.Dialog with fields
├── Select from a list of records → frappe.ui.form.MultiSelectDialog
├── Full custom page (not a form) → frappe.ui.Page
├── Customize list columns/colors → frappe.listview_settings
├── Visual board for workflow     → Kanban Board (Select field based)
├── Date-based record view        → Calendar View ({doctype}_calendar.js)
├── Hierarchical data display     → Tree View (is_tree DocType)
├── Live updates without refresh  → frappe.publish_realtime + frappe.realtime.on
├── Show background job progress  → frappe.publish_progress
├── Scan barcode/QR code          → frappe.ui.Scanner
└── Custom cell formatting        → formatters in listview_settings or form

See `references/decision-tree.md` for the complete decision tree.

Workflow 1: Dialogs (frappe.ui.Dialog)

Simple Dialog

let d = new frappe.ui.Dialog({
    title: "Enter Details",
    fields: [
        { label: "Full Name", fieldname: "full_name", fieldtype: "Data", reqd: 1 },
        { label: "Email", fieldname: "email", fieldtype: "Data", options: "Email" },
        { label: "Role", fieldname: "role", fieldtype: "Select",
          options: "Developer\nManager\nDesigner" },
    ],
    size: "small",  // "small", "large", or "extra-large"
    primary_action_label: "Create",
    primary_action(values) {
        frappe.call({
            method: "myapp.api.create_user",
            args: values,
            callback(r) {
                if (!r.exc) {
                    frappe.show_alert({ message: "User created", indicator: "green" });
                    d.hide();
                }
            }
        });
    }
});
d.show();

**Rule**: ALWAYS call `d.hide()` inside the callback, NEVER before the async call completes.

Dialog with Table Field

let d = new frappe.ui.Dialog({
    title: "Add Items",
    fields: [
        { label: "Customer", fieldname: "customer", fieldtype: "Link",
          options: "Customer", reqd: 1 },
        { fieldtype: "Section Break" },
        { label: "Items", fieldname: "items", fieldtype: "Table",
          in_place_edit: true, reqd: 1,
          fields: [
              { fieldname: "item", label: "Item", fieldtype: "Link",
                options: "Item", in_list_view: 1, reqd: 1 },
              { fieldname: "qty", label: "Qty", fieldtype: "Int",
                in_list_view: 1, default: 1 },
              { fieldname: "rate", label: "Rate", fieldtype: "Currency",
                in_list_view: 1 },
          ],
        },
    ],
    primary_action_label: "Submit",
    primary_action(values) {
        console.log(values);  // { customer: "...", items: [{item, qty, rate}] }
        d.hide();
    }
});
d.show();

**Rule**: ALWAYS set `in_list_view: 1` on table child fields you want visible. Fields without it are hidden in the grid.

Multi-Step Dialog

let d = new frappe.ui.Dialog({
    title: "Setup Wizard",
    fields: [
        // Page 1
        { fieldtype: "Section Break", label: "Step 1: Basic Info",
          collapsible: 0 },
        { label: "Name", fieldname: "name", fieldtype: "Data", reqd: 1 },
        // Page 2
        { fieldtype: "Section Break", label: "Step 2: Configuration",
          collapsible: 0 },
        { label: "Option", fieldname: "option", fieldtype: "Select",
          options: "A\nB\nC" },
    ],
    primary_action_label: "Finish",
    primary_action(values) {
        d.hide();
    }
});
d.show();

Key Dialog Methods

| Method | Purpose | |--------|---------| | `d.show()` | Display the dialog | | `d.hide()` | Close the dialog | | `d.get_values()` | Get all field values as object | | `d.set_values({field: val})` | Set field values | | `d.get_field("name")` | Get a specific field control | | `d.set_df_property("name", "hidden", 1)` | Show/hide fields dynamically | | `d.disable_primary_action()` | Grey out submit button | | `d.enable_primary_action()` | Re-enable submit button |

Workflow 2: Messages & Alerts

frappe.msgprint: Modal Message

// Simple message
frappe.msgprint("Record saved successfully");

// With options
frappe.msgprint({
    title: "Warning",
    message: "This action cannot be undone",
    indicator: "orange",     // green, blue, orange, red
    primary_action: {
        label: "Proceed",
        action() { do_something(); }
    }
});

// List of messages
frappe.msgprint({
    title: "Validation Errors",
    message: "Please fix the following:",
    as_list: true,
    i
Read more
@impertio-studio
Ships withfrappe-claude-skill-package

60 deterministic Claude AI skills for Frappe Framework & ERPNext v14-v16 development and operations

Stars on GitHub

Momentum

stars in total
200
Star history of Impertio-Studio/Frappe_Claude_Skill_Package on GitHub, a chart by star-history.com

More skills from other plugins.

1password

1password

Set up and use 1Password CLI for sign-in, desktop integration, and reading or injecting secrets.

openclaw12d393k
@openclaw@openclawInstall Skill

Questions about frappe-impl-ui-components.

Which coding agents can use frappe-impl-ui-components?
frappe-impl-ui-components installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.