ui-builder-patterns

UI Builder Patterns for ServiceNow

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "ui-builder-patterns" with this command: npx skills add groeimetai/snow-flow/groeimetai-snow-flow-ui-builder-patterns

UI Builder Patterns for ServiceNow

UI Builder (UIB) is ServiceNow's modern framework for building Next Experience workspaces and applications.

UI Builder Architecture

Component Hierarchy

UX Application └── App Shell └── Chrome (Header, Navigation) └── Pages └── Variants └── Macroponents └── Components └── Elements

Key Concepts

Concept Description

Macroponent Reusable container with components and logic

Component UI building block (list, form, button)

Data Broker Fetches and manages data for components

Client State Page-level state management

Event Communication between components

Page Structure

Page Anatomy

Page: incident_list ├── Variants │ ├── Default (desktop) │ └── Mobile ├── Data Brokers │ ├── incident_data (GraphQL) │ └── user_preferences (Script) ├── Client States │ ├── selectedRecord │ └── filterActive ├── Events │ ├── RECORD_SELECTED │ └── FILTER_APPLIED └── Layout ├── Header (macroponent) ├── Sidebar (macroponent) └── Content (macroponent)

Data Brokers

Types of Data Brokers

Type Use Case Example

GraphQL Table queries Incident list

Script Complex logic Calculated metrics

REST External APIs Weather data

Transform Data manipulation Format dates

GraphQL Data Broker

// Data Broker: incident_list // Type: GraphQL

// Query query ($limit: Int, $query: String) { GlideRecord_Query { incident( queryConditions: $query limit: $limit ) { number { value displayValue } short_description { value } priority { value displayValue } state { value displayValue } assigned_to { value displayValue } sys_id { value } } } }

// Variables (from client state or props) { "limit": 50, "query": "active=true" }

Script Data Broker (ES5)

// Data Broker: incident_metrics // Type: Script

;(function execute(inputs, outputs) { var result = { total: 0, byPriority: {}, avgAge: 0, }

var gr = new GlideRecord("incident") gr.addQuery("active", true) gr.query()

var totalAge = 0 while (gr.next()) { result.total++

// Count by priority
var priority = gr.getValue("priority")
if (!result.byPriority[priority]) {
  result.byPriority[priority] = 0
}
result.byPriority[priority]++

// Calculate age
var opened = new GlideDateTime(gr.getValue("opened_at"))
var now = new GlideDateTime()
var age = gs.dateDiff(opened, now, true)
totalAge += parseInt(age)

}

if (result.total > 0) { result.avgAge = Math.round(totalAge / result.total / 3600) // hours }

outputs.metrics = result })(inputs, outputs)

Client State Parameters

Defining Client State

// Page Client State Parameters { "selectedIncident": { "type": "string", "default": "" }, "filterQuery": { "type": "string", "default": "active=true" }, "viewMode": { "type": "string", "default": "list", "enum": ["list", "card", "split"] }, "selectedRecords": { "type": "array", "items": { "type": "string" }, "default": [] } }

Using Client State in Components

// In component configuration { "query": "@state.filterQuery", "selectedItem": "@state.selectedIncident" }

// Updating client state via event { "eventName": "NOW_RECORD_LIST#RECORD_SELECTED", "handlers": [ { "action": "UPDATE_CLIENT_STATE", "payload": { "selectedIncident": "@payload.sys_id" } } ] }

Events and Handlers

Event Types

Event Trigger Payload

NOW_RECORD_LIST#RECORD_SELECTED

Row click { sys_id, table }

NOW_BUTTON#CLICKED

Button click { label }

NOW_DROPDOWN#SELECTED

Dropdown change { value }

CUSTOM#EVENT_NAME

Custom event Custom payload

Event Handler Configuration

// Event: Record Selected { "eventName": "NOW_RECORD_LIST#RECORD_SELECTED", "handlers": [ { "action": "UPDATE_CLIENT_STATE", "payload": { "selectedIncident": "@payload.sys_id" } }, { "action": "REFRESH_DATA_BROKER", "payload": { "dataBrokerId": "incident_details" } }, { "action": "DISPATCH_EVENT", "payload": { "eventName": "INCIDENT_SELECTED", "payload": "@payload" } } ] }

Client Script Event Handler (ES5)

// Client Script for custom event handling ;(function (coeffects) { var dispatch = coeffects.dispatch var state = coeffects.state var payload = coeffects.action.payload

// Custom logic var selectedId = payload.sys_id

// Update multiple states dispatch("UPDATE_CLIENT_STATE", { selectedIncident: selectedId, detailsVisible: true, })

// Conditional dispatch if (payload.priority === "1") { dispatch("DISPATCH_EVENT", { eventName: "CRITICAL_INCIDENT_SELECTED", payload: payload, }) } })(coeffects)

Component Configuration

Common Components

Component Purpose Key Properties

now-record-list

Data table columns, query, table

now-record-form

Record form table, sysId, fields

now-button

Action button label, variant, icon

now-card

Card container header, content

now-tabs

Tab container tabs, activeTab

now-modal

Modal dialog opened, title

Record List Configuration

{ "component": "now-record-list", "properties": { "table": "incident", "query": "@state.filterQuery", "columns": [ { "field": "number", "label": "Number" }, { "field": "short_description", "label": "Description" }, { "field": "priority", "label": "Priority" }, { "field": "state", "label": "State" }, { "field": "assigned_to", "label": "Assigned To" } ], "pageSize": 20, "selectable": true, "selectedRecords": "@state.selectedRecords" } }

Form Configuration

{ "component": "now-record-form", "properties": { "table": "incident", "sysId": "@state.selectedIncident", "fields": ["short_description", "description", "priority", "assignment_group", "assigned_to"], "readOnly": false } }

Macroponents

Creating Reusable Macroponents

Macroponent: incident-summary-card ├── Properties (inputs) │ ├── incidentSysId (string) │ └── showActions (boolean) ├── Internal State │ └── expanded (boolean) ├── Data Broker │ └── incident_data (uses incidentSysId) └── Layout ├── now-card │ ├── Header: @data.incident.number │ ├── Content: @data.incident.short_description │ └── Footer: Action buttons └── now-modal (if expanded)

Macroponent Properties

{ "properties": { "incidentSysId": { "type": "string", "required": true, "description": "Sys ID of incident to display" }, "showActions": { "type": "boolean", "default": true, "description": "Show action buttons" }, "variant": { "type": "string", "default": "default", "enum": ["default", "compact", "detailed"] } } }

MCP Tool Integration

Available UIB Tools

Tool Purpose

snow_create_uib_page

Create new page

snow_create_uib_component

Add component to page

snow_create_uib_data_broker

Create data broker

snow_create_uib_client_state

Define client state

snow_create_uib_event

Configure events

snow_create_complete_workspace

Full workspace

snow_update_uib_page

Modify page

snow_validate_uib_page_structure

Validate structure

Example Workflow

// 1. Create workspace await snow_create_complete_workspace({ name: "IT Support Workspace", description: "Agent workspace for IT support", landing_page: "incident_list", })

// 2. Create data broker await snow_create_uib_data_broker({ page_id: pageId, name: "incident_list", type: "graphql", query: incidentQuery, })

// 3. Add components await snow_create_uib_component({ page_id: pageId, component: "now-record-list", properties: listConfig, })

// 4. Configure events await snow_create_uib_event({ page_id: pageId, event_name: "NOW_RECORD_LIST#RECORD_SELECTED", handlers: eventHandlers, })

Best Practices

  • Use Data Brokers - Never fetch data directly in components

  • Client State for UI - Use for filters, selections, view modes

  • Events for Communication - Decouple components via events

  • Macroponents for Reuse - Create reusable building blocks

  • GraphQL for Queries - More efficient than Script brokers

  • Validate Structure - Use validation tools before deployment

  • Mobile Variants - Create responsive variants

  • Accessibility - Follow WCAG guidelines

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

predictive-intelligence

No summary provided by upstream source.

Repository SourceNeeds Review
General

scheduled-jobs

No summary provided by upstream source.

Repository SourceNeeds Review
General

document-management

No summary provided by upstream source.

Repository SourceNeeds Review