---
sourceDocument: Australia ServiceNow AI Platform user interface
sourceDocumentLink: https://servicenow-prod.fluidtopics.net/r/platform-user-interface

 Release :

    - australia

ft:locale :

    - en-US

ft:publication_title :

    - Australia ServiceNow AI Platform user interface

ft:clusterId :

    - platux

bundleId :

    - platux

workflow :

    - Platform


---

# General guidelines for developing widgets

# General guidelines for developing widgets {#ariaid-title1}

* Release version: Australia
* 
* Updated March 12, 2026
* 
* ![](https://www.servicenow.com/docs/portal-asset/ico-clock) 4 minutes to read

When developing custom widgets, keep these general guidelines in mind for optimal performance, scalable development, and a good user experience.  

Create a default state that provides an example to the end user

:   A widget does not have instance options defined when initially added to a page. A widget in this empty state can appear blank and cause confusion. In situations where a widget requires some initial configuration, ensure that your
    widget has a default state that communicates to the admin what configuration is necessary.

    Widgets can also be created with demo data. Demo data can also be used to:  
    * Clearly demonstrate the widget functionality to the user.
    * Provide data when previewing the widget in the widget editor. (Demo data is not visible in the designer).
    {#general-guidelines-developing-widgets__ul_r3c_nsh_l1c}

    Learn more: [Tutorial: Build a custom widget](https://servicenow-prod.fluidtopics.net/dA8KV9wCs2dGGpAp1U8V_w#adv-widget-tutorial "Follow this tutorial to build a custom widget that displays Service Catalog items. Use this tutorial as a model to help you understand the advanced scripting power of the Service Portal.").

Embed a widget rather than clone when possible

:   Embedding an existing widget into your custom widget takes advantage of pre-existing functionality without cloning or duplicating code. You can still pass parameters into the embedded widget to control its behavior.

    Learn more: [Embed an existing widget](https://servicenow-prod.fluidtopics.net/dA8KV9wCs2dGGpAp1U8V_w#embed-widget "Enable the user to view and purchase Service Catalog items in the Quick Order widget by embedding the SC Catalog Item widget.")

Avoid using large data sets to improve performance

:   Querying data, evaluating ACLs, running business rules, and data processing take time and can slow performance. Determine how much data portal users need and then apply the appropriate limits and filters to your scripts and
    queries. Isolate widgets that require significant data or processing to their own separate pages in the portal. Avoid implementing the following items that use large data sets:

    * Scripted menu items that load large amounts of data, which can cause every page in the portal to load slowly.
    * Large files and attachments, such as high-definition media files or fonts from the Attachments \[sys_attachment\] table.
    * Auto-refreshing widgets. Every time a widget's client controller calls server.update(), spUtil.update(), server.refresh(), or spUtil.refresh(), the application runs the widget's server script and sends a data object back to the client.
    * Unfiltered record watchers. The recordWatch() function watches for updates to a table or filter and returns the value from the callback function. Adding filters for specific fields to watch reduces the number of calls a widget makes to the server. Specifying when to refresh widgets in response to a record producer notifying the client that there is an update in the callback function can also improve performance.
    * Server-side scripts with GlideRecord queries without the `setLimit` function. Using the `setLimit` function can restrict the number of records returned and improve response time on queries. For added flexibility, you can tie this limit to an instance option rather than assigning a hard-coded value (for example: `gr.setLimit(options.limit || 100)`).

    {#general-guidelines-developing-widgets__ul_s3c_nsh_l1c}  
    Learn more:

    * [Six common performance pitfalls in Service Portal and how to avoid them \[KB0634588\]](https://support.servicenow.com/kb?id=kb_article_view&sysparm_article=KB0634588)
    * [spUtil - recordWatch](https://www.servicenow.com/docs/access?context=spUtilAPI&version=australia&pubname=australia-api-reference&ft:locale=en-US)
    * [GlideRecord setLimit Function](https://www.servicenow.com/docs/access?context=c_GlideRecordAPI&version=australia&pubname=australia-api-reference&ft:locale=en-US)
    {#general-guidelines-developing-widgets__ul_t3c_nsh_l1c}

Create a directive instead of embedding a complex widget

:   When an embedded widget is called from the server, all the scripts associated with that widget are returned. If you only need a subsection of a widget, embedding the entire widget creates unnecessary overhead. Instead, use
    directives to share lightweight code between widgets. Directives are useful, for example, when building UI components. Complex components with server-side and client-side functionality are best left as widgets. Use a directive
    instead of an embedded widget to:

    * Share scope or custom scope behavior with multiple widgets.
    * Share a reusable, lightweight subsection of a widget.
    * Share a common UI feature, such as a list or an avatar.
    * Augment widget behavior.
    {#general-guidelines-developing-widgets__ul_u3c_nsh_l1c}

    Learn more: [Reuse components with Angular Providers](https://servicenow-prod.fluidtopics.net/HMVS9ZPxGfXLFbl2P7Y3jw "Angular Providers are reusable components that can be injected into multiple widgets. To ensure quick loading widgets and a high performing portal, create Angular Providers instead of overloading your client controllers with persistent data and additional logic. With Angular Providers, you can maintain data for the lifetime of your Service Portal and reuse components and data objects across multiple widgets.").

Use a service or factory to share data and persist state

:   Data services and factories maintain and persist state in a widget without requiring multiple calls to the server, enabling you to:

    * Keep widgets synchronized when changing records or filters.
    * Share data between widgets.
    * Develop more performant widgets.
    {#general-guidelines-developing-widgets__ul_v3c_nsh_l1c}

    Learn more: [Reuse components with Angular Providers](https://servicenow-prod.fluidtopics.net/HMVS9ZPxGfXLFbl2P7Y3jw "Angular Providers are reusable components that can be injected into multiple widgets. To ensure quick loading widgets and a high performing portal, create Angular Providers instead of overloading your client controllers with persistent data and additional logic. With Angular Providers, you can maintain data for the lifetime of your Service Portal and reuse components and data objects across multiple widgets.").

Handle events with a publish/subscribe service

:   Avoid using [$broadcast](https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$broadcast) in the DOM. $broadcast dispatches the event name to all child scopes notifying registered listeners, which can be an expensive call that requires the use of the
    $rootScope global object.

    Instead, use a publish/subscribe service to handle events. When using a publish/subscribe service, a clear relationship forms between your widgets through callback handlers. In this model, you can better control the state of your
    events.

Use REST calls or `server.get` to fetch data from the server

:   When you call `server.update()`, the entire widget is returned from the server. If your widget includes divergent code paths, multiple calls to update the server can affect performance. As a rule, use your server
    script to set up the initial state of your widget. For subsequent updates, use scripted REST APIs that call script includes on your instance. This practice:

    * Separates business logic from UI elements.
    * Centralizes your code, allowing changes to be made in one place.
    {#general-guidelines-developing-widgets__ul_w3c_nsh_l1c}
:   You can also use `server.get` to pass information to the server. Use this function along with `input.action` to execute specific parts of the server script.

Develop with localization, accessibility, and UI in mind

:   To create the best experience for your users, follow these guidelines:

    * Consider the impact of your widget in a mobile environment. For example, avoid using mouse-over and other events that do not translate to a mobile device.
    * Use SCSS variables to reuse items. See [SCSS variables](https://servicenow-prod.fluidtopics.net/Zb7jj5tl_WeluFbuaba6uw#css-variables "SCSS variables are a way to store information that you want to reuse throughout your style sheet. You can store things like colors, font stacks, or any CSS value you think you want to reuse. SCSS uses the $ symbol to make something a variable.").
    * Use variable names when using colors.
    * Wrap strings for translation in localization APIs. See [Internationalize a widget](https://servicenow-prod.fluidtopics.net/x9SILXX~ZlzcZ5nJ~utRyw "Use the ${} or gs.getMessage() syntax in the HTML Template, Client Script, or Server Script fields of a widget to tag strings for translation so you can localize your Service Portal content.").
    {#general-guidelines-developing-widgets__ul_x3c_nsh_l1c}

Remove unused Angular Providers from client script
:   For easier maintenance, remove any unused Angular Providers that were injected into the client script function statement.

Avoid using \<script\> tags in HTML templates
:   To lessen the likelihood of production issues in Service Portal, avoid using inline templates using \<script\> tags in a widget's HTML template. Instead, create a related Angular ng-template record for the widget.

