The form has 14 client scripts, the page-load takes four seconds, and three of the scripts do exactly what a UI Policy would do declaratively. The form behavior toolbox in ServiceNow has the right tools for the right jobs; teams reach past the declarative tools because client scripts feel more powerful, and the maintenance bill arrives later. The decision tree below keeps form logic maintainable.
UI Policies First
Show or hide, required or not required, read-only or editable — all declarative via UI Policy. No code, deploys cleanly through update sets, easy to audit, easy for the next maintainer to find. If the requirement is form-field visibility, mandatory state, or read-only state based on conditions over other fields, reach for UI Policy first. The condition builder handles AND/OR composition without scripting.
UI Policy use cases (no script needed):
show field X when category = "hardware"
require field Y when state = "in progress"
read-only field Z for users without role X
hide section A on initial load until trigger field set
Client Scripts When You Must
Complex form logic, asynchronous GlideAjax calls to server-side script includes, onChange transformations that compute derived values, cross-field validation with custom messages — client scripts own this territory. Use them where UI Policy cannot express the rule. The mistake is to use them for what UI Policy already does declaratively, which produces forms that are hard to audit and slow to load.
// Legitimate client script: cross-field computation
function onChange(control, oldValue, newValue, isLoading) {
if (isLoading || !newValue) return;
var weight = parseFloat(g_form.getValue('weight_kg'));
var qty = parseFloat(g_form.getValue('quantity'));
if (weight && qty) {
g_form.setValue('total_weight', (weight * qty).toFixed(2));
}
}
Reference Qualifiers Are Their Own Tool
Filtering a reference field’s options is neither UI Policy nor client script work. Use reference qualifiers — declarative, server-evaluated, no client round trip. A static qualifier (active=true^locked=false) compiles to SQL and runs fast. A dynamic qualifier (calling a script include) is more powerful and more expensive — use sparingly and never inside a tight loop or with high-cardinality reference fields.
Performance Matters
Every onChange client script is overhead. Ten onChange scripts on a heavy form and the user feels it; the cumulative latency on form load and field interaction adds up. Audit form load times for high-traffic forms (incident, service catalog items in the top 10 by volume). Consolidate overlapping scripts where possible. Convert any client script that just shows or hides a field to a UI Policy.
Testing Form Behavior
Form behavior is fragile because the dependency graph between scripts and policies is rarely documented. Add automated tests via ATF for critical forms — one test per UI Policy and per client script that matters. The test imitates a user setting field values and asserts the resulting form state. Without ATF coverage, regressions land silently and users notice when the form behaves “weirdly.”
Common Failure Modes
UI Policy and client script both touching the same field with conflicting logic — the order of evaluation is not always intuitive. Pick one tool per field; do not split visibility logic across both. Client scripts that call GlideAjax synchronously for every keystroke — convert to async patterns or debounce on the client. UI Policy conditions referring to fields that are sometimes hidden — the condition evaluates against the field’s value, which may be undefined, producing unexpected behavior.
What Changed in 2026
Workspace-rendered forms (Next Experience) handle some legacy client scripts via a compatibility shim, but new logic should target the workspace component model rather than legacy client scripts. Workspace-specific form behavior may need its own implementation; the same script does not always work identically across classic UI and workspace.
Implementation Sequence
When adding form behavior, ask first if a UI Policy expresses the requirement. If yes, use UI Policy. If no, consider whether the requirement should change to fit declarative tooling. Only when the requirement genuinely needs scripting, write a client script with a focused scope and an ATF test. Refactoring an existing form is harder than starting clean; pick one heavy form per quarter for a cleanup sprint.
What to do this week: pick the busiest form in your instance and count its UI Policies versus its client scripts; convert any script that just shows, hides, or sets read-only to a UI Policy.