@servicenow/sdk
Version:
ServiceNow SDK
480 lines (375 loc) • 20.7 kB
Markdown
---
tags: [service portal menu, angular provider, widget dependency, header footer, portal css, scss, ootb widgets, ootb pages, bootstrap, sp_instance_menu, sp_angular_provider, sp_dependency, sp_header_footer]
---
# 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.
### Menu Item Types
| Type | Additional Fields | Description |
| ------------- | -------------------------------- | ------------------------------- |
| `page` | `page` (reference, required) | Links to an SP page |
| `url` | `url`, `urlTarget` | External or internal URL |
| `sc` | (none) | Service Catalog home |
| `sc_category` | `scCategory`, `page` | Service Catalog category |
| `sc_cat_item` | `catItem`, `page` | Specific catalog item |
| `kb` | (none) | Knowledge Base home |
| `kb_topic` | `kbTopic`, `page` | Knowledge topic |
| `kb_article` | `kbArticle`, `page` | Specific knowledge article |
| `kb_category` | `kbCategory`, `page` | Knowledge category |
| `filtered` | `table`, `filter`, display fields| Dynamic content based on filter |
| `scripted` | `script` | Server-side generated items |
### Menu Widget Selection
Always use an existing OOTB menu widget. Always set the `widget` field on menu records.
| Widget Name | Typical sys_id (verify on instance) | Recommended Use |
| ---------------- | ----------------------------------------- | ---------------------------- |
| Header Menu | `5ef595c1cb12020000f8d856634c9c6e` | Standard portal navigation |
| Icon Menu List | `88979930cb01020000f8d856634c9caa` | Menu with icon per item |
| Single Icon Menu | `5edf4c21cb21020000f8d856634c9cba` | Compact icon dropdown |
### Menu Example
```typescript fluent
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
| Type | Returns | When to Use |
| ----------- | --------------------------------- | ------------------------------------------------- |
| `directive` | Directive Definition Object (DDO) | Custom HTML elements/attributes, reusable UI |
| `service` | Object with methods | Shared logic, state management, utility functions |
| `factory` | Object or primitive | Configurable 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
```typescript fluent
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.
```typescript fluent
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")
});
```
```javascript
// 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
```typescript fluent
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"
})
}
]
});
```
---
## API Reference: Header/Footer (sp_header_footer)
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.
| Record | Sys ID |
| ------------- | ---------------------------------- |
| Stock Header | `bf5ec2f2cb10120000f8d856634c9c0c` |
| Sample Footer | `feb4f763df121200ba13a4836bf26320` |
Always verify existence on instance: `{ table: "sp_header_footer", encodedQuery: "sys_id=<sys_id>" }`
### Header Example
```typescript fluent
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 Case | Variable |
| ------------------------- | ---------------------------------- |
| 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 Case | Variable |
| -------------------------------- | ------------------- |
| Default border (cards, dividers) | `$border-tertiary` |
| Medium emphasis border | `$border-secondary` |
| Strong emphasis border | `$border-primary` |
#### Text
| Use Case | Variable |
| -------------------------------- | --------------------- |
| Primary text | `$text-color` |
| Secondary text | `$text-secondary` |
| Muted / helper text | `$text-muted` |
| White text (on dark backgrounds) | `$btn-primary-color` |
#### Brand Colors
| Use Case | Variable |
| ---------------------------- | ------------------------ |
| 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.
| Variable | Value | Use Case |
| -------------- | ----- | ----------------------------------- |
| `$sp-space-1` | 4px | Icon gaps, badge padding |
| `$sp-space-2` | 8px | Input padding, label gaps |
| `$sp-space-3` | 12px | Button padding Y, tight sections |
| `$sp-space-4` | 16px | Base unit -- form group gap |
| `$sp-space-5` | 24px | Card padding, section gap |
| `$sp-space-6` | 32px | Between major sections |
| `$sp-space-7` | 48px | Page top padding, empty states |
| `$sp-space-8` | 64px | Full-bleed sections |
### Typography Scale
Every `font-size` must use a theme variable -- never a raw pixel value.
| Variable | Value | Use Case |
| ---------------- | ----- | -------------------------------- |
| `$sp-text-xs` | 12px | Badges, timestamps, captions |
| `$sp-text-sm` | 14px | Helper text, table metadata |
| `$sp-text-base` | 16px | Body, labels, table cells |
| `$sp-text-md` | 18px | Card titles, sub-headings |
| `$sp-text-lg` | 22px | Section headings |
| `$sp-text-xl` | 26px | Page title |
| `$sp-text-2xl` | 32px | Hero / banner headings |
### Icon Size Scale
| Variable | Value | Use Case |
| -------------- | ----- | ----------------------------- |
| `$sp-icon-xs` | 12px | Badge / chevron icons |
| `$sp-icon-sm` | 16px | Button / inline / alert icons |
| `$sp-icon-md` | 20px | Card / stat tile icons |
| `$sp-icon-lg` | 32px | Section / feature icons |
| `$sp-icon-xl` | 48px | Empty state / hero icons |
### Bootstrap Grid Patterns
| Layout Type | Bootstrap Classes |
| ----------------------- | ---------------------------------- |
| Full-width | `col-md-12` |
| Main + sidebar | `col-md-8` + `col-md-4` |
| Equal 2-column | `col-md-6 col-xs-12` x 2 |
| 3-column cards | `col-md-4 col-sm-6 col-xs-12` x 3 |
| 4-column stat tiles | `col-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-Pattern | Correct Replacement |
| ---------------------------------- | -------------------------------------------- |
| `style=""` inline on elements | Use SCSS class |
| Raw hex values in widget CSS | Use `$brand-primary`, `$text-color` etc. |
| `<br>` tags for spacing | Use margin/padding utilities |
| `!important` in widget CSS | Increase selector specificity |
| Input without `<label>` | Every input paired with label and matching id|
| `ng-repeat` without `track by` | Always `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:
| Name | Sys ID | Widget ID | Use Case |
| --------------------- | ---------------------------------- | ---------------------------- | --------------------------- |
| Data Table | `5001b062d7101200b0b044580e6103eb` | `widget-data-table` | Record list/table views |
| Form | `fd1f4ec347730200ba13a5554ee490c0` | `widget-form` | Full ServiceNow form |
| Typeahead Search | `fa20ec02cb31020000f8d856634c9ce9` | `typeahead-search` | Search with autocomplete |
| Faceted Search | `12fbe2d287330300a785940307cb0b1b` | `faceted_search` | Filtered search results |
| Login | `6506d341cb33020000f8d856634c9cdc` | `widget-login` | Portal login form |
| User Profile | `6e6ac664d710120023c84f80de610318` | `user-profile` | User profile card |
| Ticket Conversations | `85357f52cb30020000f8d856634c9c24` | `widget-ticket-conversation` | Activity stream |
| Ticket Attachments | `9ee37281d7033100a9ad1e173e24d457` | `widget-ticket-attachments` | File upload/attachment list |
| breadcrumbs | `0fb269305b3212000d7ec7ad31f91ae2` | `breadcrumbs` | Navigation breadcrumb trail |
| Homepage Search | `200fbd96cb20020000f8d856634c9ca1` | -- | Large search bar for landing|
| sp-user-menu | `3333b2ba5b1032000d7ec7ad31f91a27` | `sp-user-menu` | User dropdown in header |
| Stock Header | `bf5ec2f2cb10120000f8d856634c9c0c` | -- | Default portal header |
| Sample Footer | `feb4f763df121200ba13a4836bf26320` | -- | Default portal footer |
| Header Menu | `5ef595c1cb12020000f8d856634c9c6e` | -- | Top navigation menu widget |
| Simple List | `5b255672cb03020000f8d856634c9c28` | `widget-simple-list` | Minimal record list |
| Approvals | `f37aa302cb70020000f8d856634c9cfc` | -- | Pending approvals list |
| KB View | `e7ef8eb847101200ba13a5554ee49010` | -- | Knowledge article reader |
| KB Categories | `122ac7f0d7101200a9addd173e24d411` | -- | Knowledge category browsing |
| My Requests | `f1672671d7301200a9addd173e24d47d` | -- | User's open requests |
| Carousel | `cf1a5153cb21020000f8d856634c9c3c` | -- | Image/content carousel |
---
## OOTB Pages Reference
Before creating any custom page, check these commonly reusable OOTB pages:
| Title | Page ID | Sys ID | Use Case |
| -------------------- | --------------- | ---------------------------------- | ------------------------ |
| Form | `form` | `ed5f8ec347730200ba13a5554ee49046` | Generic record form |
| List | `list` | `b574e51147132100ba13a5554ee4903e` | Generic record list |
| Ticket Form | `ticket` | `84af292247132100ba13a5554ee4909e` | Ticket/case detail |
| Login | `login` | `6995a144cb11120000f8d856634c9c25` | Portal login |
| Not Found | `404` | `3c2c9063cb11020000f8d856634c9c1f` | 404 error page |
| Search | `search` | `87466b63c3223100c8b837659bba8feb` | Search results |
| Approvals | `approvals` | `d3485112cb13310000f8d856634c9c3e` | Approval list |
| My Requests | `requests` | `31ed6a51d7130200a9ad1e173e24d479` | User's requests |
| User Profile | `user_profile` | `edcbce64d710120023c84f80de610305` | User profile |
| Catalog Home (v2) | `sc_landing` | `53261e3487100300e0ef0cf888cb0b7c` | Service Catalog landing |
| Catalog Item | `sc_cat_item` | `9f12251147132100ba13a5554ee490f4` | Catalog item order form |
| KB View | `kb_view` | `db9fcab847101200ba13a5554ee490cf` | Knowledge base home |
| KB Article | `kb_article` | `dea5792147132100ba13a5554ee4902d` | Knowledge 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
### Navigation menu not showing (most common)
- 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