Skip to content
ui-actions-policies logo

UI Actions & UI Policies for ServiceNow

ui-actions-policies

Build ServiceNow UI Actions (form/list buttons, context menus) and UI Policies (conditional mandatory/visible/read-only) with server/client scripts and GlideAjax. Use snow_analyze_form before modifying forms.

groeimetai/snow-flow0installs78stars

SKILL.md

Full skill instructions

UI Actions & UI Policies for ServiceNow

UI Actions add buttons, links, and context menus. UI Policies control form field behavior dynamically.

Before modifying an existing form, reach for snow_analyze_form — it returns every active UI policy, client script, data policy, record + field ACL, and UI action on the target table in one call. Use it to answer "why is this form behaving like this?" before guessing.

UI Actions

UI Action Types

TypeLocationExample
Form ButtonForm header"Resolve Incident"
Form Context MenuRight-click menu"Copy Record"
Form LinkRelated links"View CI"
List ButtonList header"Export Selected"
List Context MenuRight-click on row"Assign to Me"
List ChoiceActions dropdown"Update State"
List LinkList header links"New Record"

Form Button UI Action (ES5)

// Table: sys_ui_action
// Name: Resolve Incident
// Table: incident
// Form button: true
// Active: true
// Condition: current.active == true && current.state != 6

// Script (Server-side - ES5 ONLY):
;(function executeAction() {
  // Validate before resolving
  if (!current.resolution_code) {
    gs.addErrorMessage("Please select a resolution code")
    action.setRedirectURL(current)
    return
  }

  if (!current.close_notes) {
    gs.addErrorMessage("Please provide resolution notes")
    action.setRedirectURL(current)
    return
  }

  // Set resolved state
  current.state = 6 // Resolved
  current.resolved_at = new GlideDateTime()
  current.resolved_by = gs.getUserID()
  current.update()

  gs.addInfoMessage("Incident " + current.number + " has been resolved")
  action.setRedirectURL(current)
})()

Client-Side UI Action (ES5)

// Table: sys_ui_action
// Name: Quick Assign
// Client: true
// Onclick: quickAssign()

// Client script (ES5 ONLY):
function quickAssign() {
  // Get current user
  var userId = g_user.userID
  var userName = g_user.getFullName()

  // Confirm action
  var confirmed = confirm("Assign this incident to yourself (" + userName + ")?")
  if (!confirmed) {
    return false
  }

  // Set the field value
  g_form.setValue("assigned_to", userId)
  g_form.setValue("assignment_group", g_user.getGroupID())

  // Save the form
  gsftSubmit(null, g_form.getFormElement(), "save")
  return false
}

List UI Action (ES5)

// Table: sys_ui_action
// Name: Close Selected Incidents
// Table: incident
// List button: true
// List choice: true
// Condition: gs.hasRole('itil')

// Script (Server-side - ES5 ONLY):
;(function executeAction() {
  // Get selected records
  var selectedRecords = RP.getParameterValue("sysparm_checked_items")
  if (!selectedRecords) {
    gs.addErrorMessage("No records selected")
    return
  }

  var sysIds = selectedRecords.split(",")
  var closedCount = 0

  for (var i = 0; i < sysIds.length; i++) {
    var gr = new GlideRecord("incident")
    if (gr.get(sysIds[i])) {
      if (gr.state != 7) {
        // Not already closed
        gr.state = 7 // Closed
        gr.closed_at = new GlideDateTime()
        gr.closed_by = gs.getUserID()
        gr.update()
        closedCount++
      }
    }
  }

  gs.addInfoMessage("Closed " + closedCount + " incident(s)")
})()

UI Action with GlideAjax (ES5)

// Client-side UI Action calling server
// Client: true
// Onclick: checkAndEscalate()

function checkAndEscalate() {
  var incidentId = g_form.getUniqueValue()

  // Check if escalation is allowed
  var ga = new GlideAjax("IncidentAjax")
  ga.addParam("sysparm_name", "canEscalate")
  ga.addParam("sysparm_incident_id", incidentId)
  ga.getXMLAnswer(function (answer) {
    var result = JSON.parse(answer)
    if (result.canEscalate) {
      // Proceed with escalation
      g_form.setValue("priority", 1)
      g_form.setValue("escalation", 1)
      gsftSubmit(null, g_form.getFormElement(), "escalate_incident")
    } else {
      alert("Cannot escalate: " + result.reason)
    }
  })
  return false
}

UI Policies

UI Policy Structure

FieldPurpose
Short descriptionPolicy name
TableTarget table
ConditionsWhen to apply
Reverse if falseUndo when condition false
On loadRun when form loads
UI Policy ActionsField behaviors

Basic UI Policy (No Script)

# UI Policy: Make Resolution Required on Resolve
Table: incident
Short description: Require resolution fields when resolving
Conditions: state = 6 (Resolved)
On load: true
Reverse if false: true

# UI Policy Actions:
- Field: resolution_code
  Mandatory: true
  Visible: true

- Field: close_notes
  Mandatory: true
  Visible: true

- Field: resolved_by
  Read only: true

UI Policy with Script (ES5)

// UI Policy Script - Execute if true
// Runs when condition becomes true (ES5 ONLY!)

function onCondition() {
  // Show/​hide fields based on category
  var category = g_form.getValue("category")

  if (category === "hardware") {
    g_form.setDisplay("cmdb_ci", true)
    g_form.setMandatory("cmdb_ci", true)
    g_form.setDisplay("software", false)
  } else if (category === "software") {
    g_form.setDisplay("software", true)
    g_form.setMandatory("software", true)
    g_form.setDisplay("cmdb_ci", false)
  }
}

Complex UI Policy Script (ES5)

// UI Policy: VIP Caller Handling
// Condition: None (script handles logic)
// On load: true
// Run scripts: true

// Script - Execute if true (ES5 ONLY!):
function onCondition() {
  var callerId = g_form.getValue("caller_id")
  if (!callerId) {
    return
  }

  // Check if VIP via GlideAjax
  var ga = new GlideAjax("UserAjax")
  ga.addParam("sysparm_name", "isVIP")
  ga.addParam("sysparm_user_id", callerId)
  ga.getXMLAnswer(function (answer) {
    var isVIP = answer === "true"

    if (isVIP) {
      // Highlight form
      g_form.flash("caller_id", "#FFD700", 0)
      g_form.showFieldMsg("caller_id", "VIP Customer", "info")

      // Set default priority
      if (!g_form.getValue("priority")) {
        g_form.setValue("priority", 2)
      }

      // Make assignment group mandatory
      g_form.setMandatory("assignment_group", true)
    }
  })
}

Dynamic Field Visibility (ES5)

// UI Policy: Show fields based on incident type
// Table: incident
// On load: true

function onCondition() {
  var incidentType = g_form.getValue("u_incident_type")

  // Reset all conditional fields
  var conditionalFields = ["u_network_details", "u_hardware_model", "u_software_name"]
  for (var i = 0; i < conditionalFields.length; i++) {
    g_form.setDisplay(conditionalFields[i], false)
    g_form.setMandatory(conditionalFields[i], false)
  }

  // Show relevant fields
  switch (incidentType) {
    case "network":
      g_form.setDisplay("u_network_details", true)
      g_form.setMandatory("u_network_details", true)
      break
    case "hardware":
      g_form.setDisplay("u_hardware_model", true)
      g_form.setMandatory("u_hardware_model", true)
      break
    case "software":
      g_form.setDisplay("u_software_name", true)
      g_form.setMandatory("u_software_name", true)
      break
  }
}

Creating via Scripts (ES5)

Create UI Action Programmatically

// Create UI Action via background script (ES5 ONLY!)
var uiAction = new GlideRecord("sys_ui_action")
uiAction.initialize()
uiAction.setValue("name", "Escalate to Manager")
uiAction.setValue("table", "incident")
uiAction.setValue("active", true)
uiAction.setValue("form_button", true)
uiAction.setValue("form_style", "btn-warning")
uiAction.setValue("hint", "Escalate this incident to the caller's manager")
uiAction.setValue("condition", "current.active == true && current.priority > 2")
uiAction.setValue(
  "script",
  "(function executeAction() {\n" +
    "    current.priority = 2;\n" +
    "    current.escalation = 1;\n" +
    '    current.work_notes = "Escalated by " + gs.getUserDisplayName();\n' +
    "    current.update();\n" +
    '    gs.addInfoMessage("Incident escalated");\n' +
    "    action.setRedirectURL(current);\n" +
    "})();",
)
uiAction.insert()

Create UI Policy Programmatically

// Create UI Policy (ES5 ONLY!)
var policy = new GlideRecord("sys_ui_policy")
policy.initialize()
policy.setValue("short_description", "Require Close Notes on Close")
policy.setValue("table", "incident")
policy.setValue("active", true)
policy.setValue("on_load", true)
policy.setValue("reverse_if_false", true)
policy.setValue("conditions", "state=7")
var policySysId = policy.insert()

// Add UI Policy Action
var action = new GlideRecord("sys_ui_policy_action")
action.initialize()
action.setValue("ui_policy", policySysId)
action.setValue("field", "close_notes")
action.setValue("mandatory", true)
action.setValue("visible", true)
action.setValue("disabled", false)
action.insert()

MCP Tool Integration

Available Tools

ToolPurpose
snow_create_ui_actionCreate UI Action
snow_create_ui_policyCreate UI Policy
snow_artifact_manage (action=find)Find existing UI elements
snow_artifact_manage (action=update)Modify UI elements

Example Workflow

// 1. Create UI Action
await snow_create_ui_action({
  name: "Approve Change",
  table: "change_request",
  form_button: true,
  condition: 'current.state == "assess"',
  script: "/​* approval script */",
})

// 2. Create UI Policy
await snow_create_ui_policy({
  short_description: "Require justification for high priority",
  table: "change_request",
  conditions: "priority=1",
  actions: [{ field: "justification", mandatory: true }],
})

Best Practices

  1. Descriptive Names - Clear purpose in name
  2. Conditions First - Use conditions before scripts
  3. Minimal Scripts - Keep scripts short
  4. Reverse If False - Clean up field states
  5. Test Thoroughly - Multiple scenarios
  6. Role Security - Add role conditions
  7. ES5 Only - No modern JavaScript syntax
  8. Form vs List - Choose appropriate action type

More skills from groeimetai

reporting-dashboards logo
groeimetai/snow-flow

reporting-dashboards

Build ServiceNow reports (list/bar/pie/line/pivot/single-score) on sys_report, sys_dashboard layouts with widget placement, scheduled report delivery, and drill-down configuration.

78 0
View
rest-integration logo
groeimetai/snow-flow

rest-integration

Make outbound REST calls from ServiceNow with sn_ws.RESTMessageV2 — basic/bearer/OAuth/API-key auth, error handling by status code, response parsing, sys_rest_message records, and retry with exponential backoff.

78 0
View
mcp-tool-discovery logo
groeimetai/snow-flow

mcp-tool-discovery

Use tool_search to discover and enable lazy-loaded Serac MCP tools (snow_*, jira_*, github_*, etc). Explains naming conventions, search strategies, and always-available activity tools.

78 0
View
atf-testing logo
groeimetai/snow-flow

atf-testing

Build ServiceNow Automated Test Framework tests and suites — impersonation, form steps, assertions, server-side script steps, test parameters, and execution via snow_create_atf_test / snow_execute_atf_test.

78 0
View
import-export logo
groeimetai/snow-flow

import-export

Move data in and out of ServiceNow — CSV parsing into import sets, GlideImportSetTransformer runs, CSV/JSON/XML exports, scheduled data sources, bulk update and deleteMultiple safety patterns.

78 0
View
discovery-patterns logo
groeimetai/snow-flow

discovery-patterns

Configure ServiceNow Discovery — schedules, IP ranges, credential affinities, MID Server assignment, custom probes/sensors, identification rules, and run-status monitoring on discovery_* tables.

78 0
View
csm-patterns logo
groeimetai/snow-flow

csm-patterns

Build ServiceNow Customer Service Management — customer_account, customer_contact, sn_customerservice_case routing, service entitlements with usage decrement, and Customer Portal case submission widgets.

78 0
View
data-policies logo
groeimetai/snow-flow

data-policies

Manage ServiceNow dictionary (sys_dictionary), table/field creation, choice lists, dictionary overrides, and sys_data_policy2 rules that enforce mandatory/read-only/visible field behavior on the data layer.

78 0
View
mobile-development logo
groeimetai/snow-flow

mobile-development

Configure ServiceNow Mobile (Now Mobile/Agent) — sys_sg_mobile_app screens, card builders, push notifications, offline sync rules, mobile actions for barcode/GPS, and offline-queue change processing.

78 0
View
email-notifications logo
groeimetai/snow-flow

email-notifications

Create ServiceNow sysevent_email_action notifications — templates with substitution variables, mail scripts for dynamic content/recipients/attachments, custom events, weights, and digest configuration.

78 0
View
es5-compliance logo
groeimetai/snow-flow

es5-compliance

Enforce ES5-only syntax for ServiceNow server-side scripts (Rhino engine) — convert const/let, arrow functions, template literals, destructuring, for-of, and async/await to ES5 equivalents.

78 0
View
change-management logo
groeimetai/snow-flow

change-management

Create and transition ServiceNow change requests (normal/standard/emergency), change tasks, affected CIs, approval routing, CAB scheduling, and conflict detection across maintenance windows.

78 0
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View