UI Generation from Natural Language
SkillDev toolsGenerate platform UI components from natural language, including client scripts, data binding, event handlers, pages, and UI Builder experiences.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the UI Generation from Natural Language skill
What this skill tells your AI
The instructions your AI receives, as published by happy-technologies-llc/happy-platform-skills in skills/development/ui-generation/SKILL.md and read by ahel’s review.
Overview
This skill covers generating ServiceNow UI components from natural language descriptions:
- Creating client scripts (onChange, onLoad, onSubmit, onCellEdit) for forms and lists
- Building data binding configurations for UI Builder and Service Portal widgets
- Generating event handler logic for user interactions
- Creating UI Pages with Jelly/HTML templates and processing scripts
- Building Service Portal widgets with AngularJS controllers and HTML templates
- Generating UI Builder experience pages with data resources and event mappings
- Producing UI macros for reusable form decorations and formatters
When to use: When developers or citizen developers need to create UI components from business requirements described in plain language, or when rapidly prototyping form behaviors, portal widgets, or workspace pages.
Prerequisites
- Roles:
admin,personalize_form, orsp_admin(for Service Portal widgets) - Plugins:
com.glide.ui.ui_page(UI Pages),com.glide.service-portal(Service Portal),com.sn_ui_builder(UI Builder) - Access: Write access to
sys_script_client,sys_ui_page,sp_widget,sys_ux_page_registrytables - Knowledge: JavaScript fundamentals, GlideForm API, AngularJS basics (for Service Portal), UI Builder concepts
- Related Skills:
development/client-scriptsfor client script patterns,catalog/ui-policiesfor catalog form behavior
Procedure
Step 1: Parse the Natural Language Description
Analyze the user request to identify:
- Component type: Client script, UI page, Service Portal widget, UI Builder page, UI macro
- Target table/form: Which table or form the component applies to
- Behavior: What should happen (show/hide fields, validate data, fetch records, render UI)
- Trigger: What event initiates the behavior (field change, form load, button click, page load)
- Data dependencies: What data the component needs to read or write
Step 2: Query Existing Components for Patterns
MCP Approach:
Tool: SN-Query-Table
Parameters:
table_name: sys_script_client
query: table=incident^active=true^typeLIKEonChange
fields: sys_id,name,table,type,field_name,script,active,ui_type
limit: 10
REST Approach:
GET /api/now/table/sys_script_client
?sysparm_query=table=incident^active=true^typeLIKEonChange
&sysparm_fields=sys_id,name,table,type,field_name,script,active,ui_type
&sysparm_limit=10
Step 3: Generate Client Scripts
Translate natural language to GlideForm API calls. Common patterns:
onChange -- Show/Hide Fields:
MCP Approach:
Tool: SN-Create-Record
Parameters:
table_name: sys_script_client
data:
name: "Show VPN fields when category is Network"
table: incident
type: onChange
field_name: category
ui_type: 0
active: true
script: |
function onChange(control, oldValue, newValue, isLoading) {
if (isLoading) return;
var isNetwork = (newValue == 'network');
g_form.setVisible('u_vpn_type', isNetwork);
g_form.setVisible('u_network_segment', isNetwork);
if (isNetwork) {
g_form.setMandatory('u_vpn_type', true);
} else {
g_form.setMandatory('u_vpn_type', false);
}
}
REST Approach:
POST /api/now/table/sys_script_client
Body: {
"name": "Show VPN fields when category is Network",
"table": "incident",
"type": "onChange",
"field_name": "category",
"ui_type": "0",
"active": "true",
"script": "function onChange(control, oldValue, newValue, isLoading) { ... }"
}
Step 4: Generate onLoad Scripts for Form Initialization
MCP Approach:
Tool: SN-Create-Record
Parameters:
table_name: sys_script_client
data:
name: "Initialize priority banner on form load"
table: incident
type: onLoad
ui_type: 0
active: true
script: |
function onLoad() {
var priority = g_form.getValue('priority');
if (priority == '1') {
g_form.showFieldMsg('priority', 'Critical incident - follow P1 procedures', 'error');
g_form.setReadOnly('category', true);
g_form.setReadOnly('subcategory', true);
}
}
Step 5: Generate onSubmit Validation Scripts
MCP Approach:
Tool: SN-Create-Record
Parameters:
table_name: sys_script_client
data:
name: "Validate resolution notes before close"
table: incident
type: onSubmit
ui_type: 0
active: true
script: |
function onSubmit() {
var state = g_form.getValue('state');
if (state == '6') {
var resolution = g_form.getValue('close_notes');
if (!resolution || resolution.trim().length < 20) {
g_form.showFieldMsg('close_notes', 'Resolution notes must be at least 20 characters', 'error');
return false;
}
}
return true;
}
Step 6: Generate Service Portal Widgets
MCP Approach:
Tool: SN-Create-Record
Parameters:
table_name: sp_widget
data:
name: "Team Incident Dashboard"
id: "team-incident-dashboard"
template: |
<div class="panel panel-default">
<div class="panel-heading"><h3>{{c.data.title}}</h3></div>
<div class="panel-body">
<div ng-repeat="inc in c.data.incidents track by inc.sys_id">
<div class="alert alert-{{inc.priorityClass}}">
<strong>{{inc.number}}</strong> - {{inc.short_description}}
<span class="pull-right badge">{{inc.state}}</span>
</div>
</div>
<p ng-if="c.data.incidents.length === 0">No open incidents.</p>
</div>
</div>
client_script: |
api.controller = function($scope) {
var c = this;
};
server_script: |
(function() {
data.title = "My Team's Open Incidents";
var gr = new GlideRecord('incident');
gr.addQuery('assignment_group', gs.getUser().getMyGroups());
gr.addActiveQuery();
gr.orderByDesc('priority');
gr.setLimit(20);
gr.query();
data.incidents = [];
while (gr.next()) {
data.incidents.push({
sys_id: gr.getUniqueValue(),
number: gr.getValue('number'),
short_description: gr.getValue('short_description'),
state: gr.getDisplayValue('state'),
priority: gr.getValue('priority'),
priorityClass: {'1':'danger','2':'warning','3':'info','4':'success'}[gr.getValue('priority')] || 'default'
});
}
})();
REST Approach:
POST /api/now/table/sp_widget
Body: {
"name": "Team Incident Dashboard",
"id": "team-incident-dashboard",
"template": "<div class='panel panel-default'>...</div>",
"client_script": "api.controller = function($scope) { var c = this; };",
"server_script": "(function() { ... })();"
}
Step 7: Generate UI Builder Experience Pages
MCP Approach:
Tool: SN-Create-Record
Parameters:
table_name: sys_ux_page_registry
data:
title: "Executive Incident Overview"
path: /executive-incident-overview
description: "Executive dashboard showing incident metrics and trends"
category: workspace
active: true
Configure data resources for the page:
Tool: SN-Create-Record
Parameters:
table_name: sys_ux_data_broker_transform
data:
name: "Incident Metrics Data Resource"
page: "<page_sys_id>"
table: incident
query: "active=true^priority<=2"
fields: "number,short_description,priority,state,assigned_to,sys_created_on"
max_rows: 50
Step 8: Generate Event Handlers
Configure UI Builder event-to-action mappings:
MCP Approach:
Tool: SN-Create-Record
Parameters:
table_name: sys_ux_event
data:
name: "Row Click Navigate to Record"
page: "<page_sys_id>"
component: "<component_sys_id>"
event_name: "click"
action_type: "navigate"
action_config: {
"route": "/record/incident/${sys_id}",
"target": "_self"
}
Step 9: Generate UI Macros for Form Decorations
MCP Approach:
Tool: SN-Create-Record
Parameters:
table_name: sys_ui_macro
data:
name: "sla_countdown_banner"
description: "Displays a countdown timer for SLA breach on incident form"
xml: |
<?xml version="1.0" encoding="utf-8"?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide">
<g:evaluate var="jvar_sla_info" expression="
var sla = new GlideRecord('task_sla');
sla.addQuery('task', current.sys_id);
sla.addQuery('has_breached', false);
sla.addActiveQuery();
sla.orderBy('planned_end_time');
sla.setLimit(1);
sla.query();
sla.next() ? sla.getDisplayValue('planned_end_time') : 'N/A';
"/>
<div style="background:#fff3cd;padding:10px;border-radius:4px;margin-bottom:10px;">
<strong>SLA Target:</strong> ${jvar_sla_info}
</div>
</j:jelly>
Step 10: Validate and Test Generated Components
MCP Approach:
Tool: SN-Query-Table
Parameters:
table_name: sys_script_client
query: sys_id=<created_sys_id>
fields: sys_id,name,table,type,active,sys_updated_on
limit: 1
Verify no script syntax errors by checking the sys_update_xml table for recent update records:
Tool: SN-Query-Table
Parameters:
table_name: sys_update_xml
query: name=sys_script_client_<sys_id>^ORDERBYDESCsys_created_on
fields: sys_id,name,action,sys_created_on
limit: 1
Tool Usage
| Tool | Purpose | When to Use |
|---|---|---|
| SN-Query-Table | Find existing UI components for patterns | Pattern discovery, validation |
| SN-Create-Record | Create client scripts, widgets, UI pages | Building new UI components |
| SN-Update-Record | Modify scripts, templates, configurations | Iterating on generated components |
| SN-Get-Table-Schema | Discover field names for data binding | Understanding form fields and data model |
Best Practices
- Always set
ui_typecorrectly -- use0for Desktop,1for Mobile/Service Portal,2for Both - Use
g_formAPI methods rather than direct DOM manipulation for client scripts - Minimize server calls in client scripts -- use GlideAjax for async server lookups
- Scope client scripts appropriately -- avoid global scope pollution with IIFEs
- Test on multiple browsers -- avoid browser-specific JavaScript features
- Include null checks in all generated onChange handlers for empty field values
- Use
isLoadingguard in onChange scripts to prevent execution during form load - Set widgets to read-only during server calls to prevent double-submission
- Follow accessibility standards -- include ARIA labels and keyboard navigation in custom widgets
- Version control -- always associate UI components with an update set before creation
Troubleshooting
| Issue | Cause | Resolution |
|---|---|---|
| Client script not firing | Wrong type or field_name value | Verify type matches event and field_name matches column name |
| g_form undefined error | Script running outside form context | Ensure script is attached to correct table and ui_type |
| Widget data not loading | Server script GlideRecord query error | Check table permissions and query syntax in server script |
| UI page blank | Jelly syntax error in XML | Validate XML structure and check for unescaped characters |
| Event handler not responding | Component ID mismatch | Verify component sys_id in event configuration |
| Form fields not hiding | Field name vs label mismatch | Use column name (e.g., u_vpn_type) not label |
Examples
Example 1: Natural Language to Client Script
Input: "When someone selects 'Hardware' as the category on the incident form, make the model and serial number fields mandatory and show a message to fill them in."
Generated: onChange client script on incident.category that calls g_form.setMandatory() and g_form.showFieldMsg() for u_model and u_serial_number when newValue == 'hardware'.
Example 2: Natural Language to Service Portal Widget
Input: "Create a widget that shows the logged-in user's open requests with status bars showing percentage complete."
Generated: Service Portal widget with server script querying sc_req_item for the current user, client-side AngularJS rendering with Bootstrap progress bars, and click-to-navigate functionality.
Example 3: Natural Language to UI Builder Page
Input: "Build a workspace page that shows a chart of incidents by priority and a list of my team's open incidents below it."
Generated: UI Builder page registration with two data resources (aggregation for chart, list for table), a bar chart component bound to priority aggregation, and a data table component with row-click navigation.
Related Skills
development/client-scripts- In-depth client script development patternsdevelopment/ui-actions- UI action buttons and linkscatalog/ui-policies- Catalog-specific UI policiesdevelopment/scripted-rest-apis- Backend APIs for widget datagenai/flow-generation- Flow Designer automation for UI-triggered processes
Signals
- GitHub stars
- 37
- Forks
- 13
- Last commit
- Jul 2026
Advanced
- Catalog kind
- skill
- Gateway key
ui-generation- Source
- github.com/happy-technologies-llc/happy-platform-skills