โ† Back to list
groeimetai

ui-builder-patterns

by groeimetai

๐Ÿค– AI-powered ServiceNow development with 400+ MCP tools. Works with Claude, GPT, Gemini, Ollama & 75+ providers. Deploy widgets, manage incidents, automate workflows - all through natural language. Open-source Build Agent alternative.

โญ 42๐Ÿด 9๐Ÿ“… Jan 23, 2026

SKILL.md


name: ui-builder-patterns description: This skill should be used when the user asks to "create workspace", "UI Builder", "UIB", "workspace page", "macroponent", "data broker", "UX page", "configurable workspace", or any ServiceNow UI Builder and Next Experience development. license: Apache-2.0 compatibility: Designed for Snow-Code and ServiceNow development metadata: author: groeimetai version: "1.0.0" category: servicenow tools:

  • snow_workspace_create
  • snow_query_table
  • snow_find_artifact
  • snow_execute_script_with_output

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

ConceptDescription
MacroponentReusable container with components and logic
ComponentUI building block (list, form, button)
Data BrokerFetches and manages data for components
Client StatePage-level state management
EventCommunication 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

TypeUse CaseExample
GraphQLTable queriesIncident list
ScriptComplex logicCalculated metrics
RESTExternal APIsWeather data
TransformData manipulationFormat 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

EventTriggerPayload
NOW_RECORD_LIST#RECORD_SELECTEDRow click{ sys_id, table }
NOW_BUTTON#CLICKEDButton click{ label }
NOW_DROPDOWN#SELECTEDDropdown change{ value }
CUSTOM#EVENT_NAMECustom eventCustom 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

ComponentPurposeKey Properties
now-record-listData tablecolumns, query, table
now-record-formRecord formtable, sysId, fields
now-buttonAction buttonlabel, variant, icon
now-cardCard containerheader, content
now-tabsTab containertabs, activeTab
now-modalModal dialogopened, 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

ToolPurpose
snow_create_uib_pageCreate new page
snow_create_uib_componentAdd component to page
snow_create_uib_data_brokerCreate data broker
snow_create_uib_client_stateDefine client state
snow_create_uib_eventConfigure events
snow_create_complete_workspaceFull workspace
snow_update_uib_pageModify page
snow_validate_uib_page_structureValidate 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

  1. Use Data Brokers - Never fetch data directly in components
  2. Client State for UI - Use for filters, selections, view modes
  3. Events for Communication - Decouple components via events
  4. Macroponents for Reuse - Create reusable building blocks
  5. GraphQL for Queries - More efficient than Script brokers
  6. Validate Structure - Use validation tools before deployment
  7. Mobile Variants - Create responsive variants
  8. Accessibility - Follow WCAG guidelines

Score

Total Score

75/100

Based on repository quality metrics

โœ“SKILL.md

SKILL.mdใƒ•ใ‚กใ‚คใƒซใŒๅซใพใ‚Œใฆใ„ใ‚‹

+20
โœ“LICENSE

ใƒฉใ‚คใ‚ปใƒณใ‚นใŒ่จญๅฎšใ•ใ‚Œใฆใ„ใ‚‹

+10
โœ“่ชฌๆ˜Žๆ–‡

100ๆ–‡ๅญ—ไปฅไธŠใฎ่ชฌๆ˜ŽใŒใ‚ใ‚‹

+10
โ—‹ไบบๆฐ—

GitHub Stars 100ไปฅไธŠ

0/15
โœ“ๆœ€่ฟ‘ใฎๆดปๅ‹•

1ใƒถๆœˆไปฅๅ†…ใซๆ›ดๆ–ฐ

+10
โ—‹ใƒ•ใ‚ฉใƒผใ‚ฏ

10ๅ›žไปฅไธŠใƒ•ใ‚ฉใƒผใ‚ฏใ•ใ‚Œใฆใ„ใ‚‹

0/5
โœ“Issue็ฎก็†

ใ‚ชใƒผใƒ—ใƒณIssueใŒ50ๆœชๆบ€

+5
โœ“่จ€่ชž

ใƒ—ใƒญใ‚ฐใƒฉใƒŸใƒณใ‚ฐ่จ€่ชžใŒ่จญๅฎšใ•ใ‚Œใฆใ„ใ‚‹

+5
โœ“ใ‚ฟใ‚ฐ

1ใคไปฅไธŠใฎใ‚ฟใ‚ฐใŒ่จญๅฎšใ•ใ‚Œใฆใ„ใ‚‹

+5

Reviews

๐Ÿ’ฌ

Reviews coming soon