Skip to main content
Version: 4.8.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