Skip to main content
Version: Latest (4.6.0)

Service Portal Extended Reference

Extended reference for ServiceNow Service Portal covering menus, angular providers, widget dependencies, headers/footers, CSS/theming, out-of-the-box widgets and pages, and troubleshooting.

API Reference: Menu (sp_instance_menu)

For the full property reference (menus and menu items), see the spmenu-api topic.

TypeAdditional FieldsDescription
pagepage (reference, required)Links to an SP page
urlurl, urlTargetExternal or internal URL
sc(none)Service Catalog home
sc_categoryscCategory, pageService Catalog category
sc_cat_itemcatItem, pageSpecific catalog item
kb(none)Knowledge Base home
kb_topickbTopic, pageKnowledge topic
kb_articlekbArticle, pageSpecific knowledge article
kb_categorykbCategory, pageKnowledge category
filteredtable, filter, display fieldsDynamic content based on filter
scriptedscriptServer-side generated items

Always use an existing OOTB menu widget. Always set the widget field on menu records.

Widget NameTypical sys_id (verify on instance)Recommended Use
Header Menu5ef595c1cb12020000f8d856634c9c6eStandard portal navigation
Icon Menu List88979930cb01020000f8d856634c9caaMenu with icon per item
Single Icon Menu5edf4c21cb21020000f8d856634c9cbaCompact icon dropdown
import "@servicenow/sdk/global";
import { SPMenu } from "@servicenow/sdk/core";

export const mainMenu = SPMenu({
$id: Now.ID["main_menu"],
title: "Main Menu",
widget: "5ef595c1cb12020000f8d856634c9c6e",
items: [
{
$id: Now.ID["home_item"],
type: "page",
label: "Home",
page: "<home_page_sys_id>",
glyph: "home",
order: 100
},
{
$id: Now.ID["services_item"],
type: "sc",
label: "Services",
glyph: "briefcase",
order: 200,
childItems: [
{
$id: Now.ID["it_services"],
type: "sc_category",
label: "IT Services",
scCategory: "<it_category_sys_id>",
page: "<catalog_page_sys_id>",
order: 100
}
]
},
{
$id: Now.ID["kb_item"],
type: "kb",
label: "Knowledge",
glyph: "book",
order: 300
}
]
});

API Reference: Angular Provider (sp_angular_provider)

For the full property reference, see the spangularprovider-api topic.

Provider Types

TypeReturnsWhen to Use
directiveDirective Definition Object (DDO)Custom HTML elements/attributes, reusable UI
serviceObject with methodsShared logic, state management, utility functions
factoryObject or primitiveConfigurable objects, API integration layers

Provider Guidelines

  • Function name MUST match the name field exactly
  • Services and factories must return an object (not this, not primitives)
  • Directives must return a Directive Definition Object
  • Link providers to widgets via angularProviders array in SPWidget()
  • Avoid circular dependencies between providers
  • Use string concatenation for HTML inside template literals to avoid quote conflicts

Provider Example: Service

import "@servicenow/sdk/global";
import { SPAngularProvider } from "@servicenow/sdk/core";

export const dataService = SPAngularProvider({
$id: Now.ID["data_service"],
name: "dataService",
type: "service",
script: `
function dataService($http) {
return {
getRecords: function(table, limit) {
return $http.get('/api/now/table/' + table, {
params: { sysparm_limit: limit || 10 }
});
}
};
}
`
});

Linking Provider to Widget

Widget client scripts, server scripts, HTML, and CSS use Now.include() because the Service Portal widget runtime does not support modules.

import { SPWidget } from "@servicenow/sdk/core";
import { dataService } from "../../sp-angular-provider/provider.now";

export const myWidget = SPWidget({
$id: Now.ID["my_widget"],
name: "My Widget",
angularProviders: [dataService],
clientScript: Now.include("./client_script.js"),
htmlTemplate: Now.include("./template.html"),
serverScript: Now.include("./server_script.js")
});
// client_script.js
api.controller = function (dataService) {
var c = this;
dataService.getRecords("incident", 5).then(function (response) {
c.data.records = response.data.result;
});
};

API Reference: Widget Dependency (sp_dependency)

For the full property reference (dependencies, JsInclude, CssInclude), see the spwidgetdependency-api topic.

Bundled Libraries (Do NOT Re-Add)

SP already includes these globally. Adding them again causes version conflicts:

  • jQuery
  • AngularJS
  • Bootstrap 3 CSS/JS
  • Bootstrap 3 Glyphicons

Dependency Guidelines

  • Lower order numbers load first. Always load base libraries before plugins.
  • Use minified CDN URLs with version pinning (e.g., library@4.17.21)
  • One dependency per library -- share across multiple widgets
  • Always use HTTPS URLs
  • Link dependencies to widgets via dependencies array in SPWidget()

Dependency Example

import "@servicenow/sdk/global";
import { SPWidgetDependency, JsInclude, CssInclude } from "@servicenow/sdk/core";

export const select2Dep = SPWidgetDependency({
$id: Now.ID["select2_dep"],
name: "Select2",
jsIncludes: [
{
order: 100,
include: JsInclude({
$id: Now.ID["select2_js"],
name: "Select2 JS",
url: "https://cdn.jsdelivr.net/npm/select2@4.1.0/dist/js/select2.min.js"
})
}
],
cssIncludes: [
{
order: 100,
include: CssInclude({
$id: Now.ID["select2_css"],
name: "Select2 CSS",
url: "https://cdn.jsdelivr.net/npm/select2@4.1.0/dist/css/select2.min.css"
})
}
]
});

Headers and footers have no dedicated Fluent API. Use the generic Record() constructor. For the property reference, see the SPHeaderFooter topic.

OOTB Headers and Footers

Always reuse OOTB headers and footers first. Only create custom when explicitly requested.

RecordSys ID
Stock Headerbf5ec2f2cb10120000f8d856634c9c0c
Sample Footerfeb4f763df121200ba13a4836bf26320

Always verify existence on instance: { table: "sp_header_footer", encodedQuery: "sys_id=<sys_id>" }

Header Example

import "@servicenow/sdk/global";
import { Record } from "@servicenow/sdk/core";

export const customHeader = Record({
$id: Now.ID["custom_header"],
table: "sp_header_footer",
data: {
name: "Custom Portal Header",
template: Now.include("./header_template.html"),
client_script: Now.include("./header_client.js"),
css: Now.include("./header_styles.css")
}
});

CSS and Theming Reference

SCSS Variable Rules for Widget CSS

Never invent custom SCSS variable names. Service Portal compiles widget CSS as SCSS with only the portal theme's css_variables injected. Undefined variables are silently dropped.

Before writing any widget CSS:

  1. Look up the portal's theme from the portal definition
  2. Only use SCSS variables from the theme's css_variables or from the extended Bootstrap/SP defaults
  3. If a needed variable does not exist, use SCSS functions (darken(), lighten(), rgba()) on an existing variable
  4. Never use hardcoded hex, rgb, or rgba values

Extended Bootstrap/SP Defaults (Always Available)

$border-radius-base -- $border-radius-large -- $border-radius-small -- $font-size-base -- $font-size-small -- $font-size-large -- $btn-primary-color -- $panel-primary-text -- $link-color -- $state-success-bg -- $state-warning-bg -- $state-danger-bg -- $state-info-bg -- $alert-success-border -- $alert-warning-border -- $alert-danger-border -- $alert-info-border -- $body-bg -- $component-active-bg -- $btn-default-border -- $panel-border-color -- $input-border -- $input-border-focus

Coral Theme SCSS Variable Reference

Backgrounds

Use CaseVariable
Card / surface background$background-primary
Page background$sp-page-bg
Subtle / muted background$background-secondary
Heavier subtle background$background-tertiary
Input field background$sp-form-field--background-color

Borders

Use CaseVariable
Default border (cards, dividers)$border-tertiary
Medium emphasis border$border-secondary
Strong emphasis border$border-primary

Text

Use CaseVariable
Primary text$text-color
Secondary text$text-secondary
Muted / helper text$text-muted
White text (on dark backgrounds)$btn-primary-color

Brand Colors

Use CaseVariable
Primary brand$brand-primary
Primary dark (hover)$brand-primary-dark
Primary lighter (highlights)$brand-primary-lighter
Success$brand-success
Warning$brand-warning
Danger$brand-danger
Info$brand-info
Link color$link-color

Spacing Scale

Use only these values. Never use arbitrary pixel values.

VariableValueUse Case
$sp-space-14pxIcon gaps, badge padding
$sp-space-28pxInput padding, label gaps
$sp-space-312pxButton padding Y, tight sections
$sp-space-416pxBase unit -- form group gap
$sp-space-524pxCard padding, section gap
$sp-space-632pxBetween major sections
$sp-space-748pxPage top padding, empty states
$sp-space-864pxFull-bleed sections

Typography Scale

Every font-size must use a theme variable -- never a raw pixel value.

VariableValueUse Case
$sp-text-xs12pxBadges, timestamps, captions
$sp-text-sm14pxHelper text, table metadata
$sp-text-base16pxBody, labels, table cells
$sp-text-md18pxCard titles, sub-headings
$sp-text-lg22pxSection headings
$sp-text-xl26pxPage title
$sp-text-2xl32pxHero / banner headings

Icon Size Scale

VariableValueUse Case
$sp-icon-xs12pxBadge / chevron icons
$sp-icon-sm16pxButton / inline / alert icons
$sp-icon-md20pxCard / stat tile icons
$sp-icon-lg32pxSection / feature icons
$sp-icon-xl48pxEmpty state / hero icons

Bootstrap Grid Patterns

Layout TypeBootstrap Classes
Full-widthcol-md-12
Main + sidebarcol-md-8 + col-md-4
Equal 2-columncol-md-6 col-xs-12 x 2
3-column cardscol-md-4 col-sm-6 col-xs-12 x 3
4-column stat tilescol-md-3 col-sm-6 col-xs-12 x 4

Always add col-xs-12 -- every column must stack on mobile.

CSS Anti-Patterns

Anti-PatternCorrect Replacement
style="" inline on elementsUse SCSS class
Raw hex values in widget CSSUse $brand-primary, $text-color etc.
<br> tags for spacingUse margin/padding utilities
!important in widget CSSIncrease selector specificity
Input without <label>Every input paired with label and matching id
ng-repeat without track byAlways track by item.sys_id
Missing type on <button>Always type="button" or type="submit"
GlideRecord without setLimit()Always setLimit(n)

OOTB Widgets Reference

Before creating any custom widget, check these commonly reusable OOTB widgets:

NameSys IDWidget IDUse Case
Data Table5001b062d7101200b0b044580e6103ebwidget-data-tableRecord list/table views
Formfd1f4ec347730200ba13a5554ee490c0widget-formFull ServiceNow form
Typeahead Searchfa20ec02cb31020000f8d856634c9ce9typeahead-searchSearch with autocomplete
Faceted Search12fbe2d287330300a785940307cb0b1bfaceted_searchFiltered search results
Login6506d341cb33020000f8d856634c9cdcwidget-loginPortal login form
User Profile6e6ac664d710120023c84f80de610318user-profileUser profile card
Ticket Conversations85357f52cb30020000f8d856634c9c24widget-ticket-conversationActivity stream
Ticket Attachments9ee37281d7033100a9ad1e173e24d457widget-ticket-attachmentsFile upload/attachment list
breadcrumbs0fb269305b3212000d7ec7ad31f91ae2breadcrumbsNavigation breadcrumb trail
Homepage Search200fbd96cb20020000f8d856634c9ca1--Large search bar for landing
sp-user-menu3333b2ba5b1032000d7ec7ad31f91a27sp-user-menuUser dropdown in header
Stock Headerbf5ec2f2cb10120000f8d856634c9c0c--Default portal header
Sample Footerfeb4f763df121200ba13a4836bf26320--Default portal footer
Header Menu5ef595c1cb12020000f8d856634c9c6e--Top navigation menu widget
Simple List5b255672cb03020000f8d856634c9c28widget-simple-listMinimal record list
Approvalsf37aa302cb70020000f8d856634c9cfc--Pending approvals list
KB Viewe7ef8eb847101200ba13a5554ee49010--Knowledge article reader
KB Categories122ac7f0d7101200a9addd173e24d411--Knowledge category browsing
My Requestsf1672671d7301200a9addd173e24d47d--User's open requests
Carouselcf1a5153cb21020000f8d856634c9c3c--Image/content carousel

OOTB Pages Reference

Before creating any custom page, check these commonly reusable OOTB pages:

TitlePage IDSys IDUse Case
Formformed5f8ec347730200ba13a5554ee49046Generic record form
Listlistb574e51147132100ba13a5554ee4903eGeneric record list
Ticket Formticket84af292247132100ba13a5554ee4909eTicket/case detail
Loginlogin6995a144cb11120000f8d856634c9c25Portal login
Not Found4043c2c9063cb11020000f8d856634c9c1f404 error page
Searchsearch87466b63c3223100c8b837659bba8febSearch results
Approvalsapprovalsd3485112cb13310000f8d856634c9c3eApproval list
My Requestsrequests31ed6a51d7130200a9ad1e173e24d479User's requests
User Profileuser_profileedcbce64d710120023c84f80de610305User profile
Catalog Home (v2)sc_landing53261e3487100300e0ef0cf888cb0b7cService Catalog landing
Catalog Itemsc_cat_item9f12251147132100ba13a5554ee490f4Catalog item order form
KB Viewkb_viewdb9fcab847101200ba13a5554ee490cfKnowledge base home
KB Articlekb_articledea5792147132100ba13a5554ee4902dKnowledge article reader

Troubleshooting

Portal not accessible

  • Verify urlSuffix is unique and does not conflict with existing portals
  • Check user has access permissions

Theme not applying

  • Confirm theme sys_id exists on the instance
  • Verify theme is linked to portal (sp_portal.theme)
  • Check SCSS compilation errors in browser console
  • Verify portal has theme configured
  • Verify theme has header configured (sp_header_footer)
  • Verify portal has mainMenu configured
  • Query sp_widget to confirm the menu widget sys_id is correct on this instance

Widget not displaying

  • Check widget is active
  • Verify page/instance configuration
  • Check browser console for JavaScript errors

Data not updating in widget

  • Verify server script IIFE syntax is correct
  • Check c.server.get() / c.server.update() calls match input.action handling in server script

Styling issues

  • Confirm SCSS token variables are used (not raw hex)
  • Check Bootstrap 3 class names (not Bootstrap 4/5)
  • Confirm turnOffScssCompilation is false on theme

CSS variables not working

  • Verify sp-rgb() is only used when a --now-* token exists
  • Never invent token names -- use hex directly when no token exists

Library not loading

  • Verify CDN URL is accessible from the instance network
  • Check order values -- base libraries must load before plugins
  • Confirm dependency is linked to widget via dependencies array

Provider not available in widget

  • Verify provider is in angularProviders array on SPWidget()
  • Check function name matches name field exactly
  • Verify script syntax is valid