Using Next Experience Components in Service Portal

There’s many cases where a developer might have the same requirements across both Next Experience and Service Portal. For example, the requirement might be to have the following “user card” available in both UI Builder as a component, and Service Portal as a widget:

A “user card”

This scenario will become increasingly common as the focus for development shifts to Next Experience, yet with “portals” still being delivered in Service Portal.

Next Experience is a completely different framework to Service Portal though, and to implement the same requirements across both generally means a duplication of effort, and double the amount of code to maintain. Where possible, this is something that developers will want to avoid.

Although it’s not an officially supported method, it’s actually quite easy to make use of a Next Experience component inside a Service Portal widget, and in this post I’m going to show you how. What this means is that developers will be able to write the code for the component once, and leverage it across both Next Experience and Service Portal interfaces.

The Component

Let’s use the “user card” component shown above as an example. For the purposes of this post I’m not going to go into detail about how to create this component, as that’s outside the scope of what I’m trying to explain. But lets assume the component is called snc-wds-user-card-full, and is already deployed to the instance as part of a package called snc-wds-user-cards.

The package of your component is what you supplied to the --name parameter when initially creating your component project. You can find it at the top of your package.json file, as the value for the name property.

When a component project is deployed to an instance, it and all its dependencies are built into a source script file and stored in the sys_ux_lib_source_script table. Each of the records in that table are accessible on the instance at the following path:

/uxasset/externals/PACKAGE_NAME/index.jsdbx

Replacing PACKAGE_NAME with the name of your component’s package. For example:

/uxasset/externals/snc-wds-user-cards/index.jsdbx

The Widget

So we now know where the source script for the component is. How do we include that and make use of it in a widget?

The source script file exports an ECMAScript module, so we need to import that into our widget. There are a few ways that we can do this but the simplest way is to use JavaScript’s import() function directly inside our widget’s link function like so:

function link(scope, element, attrs, controller) {

	(async () => {

		// replace the URL in the following with that of your component's source script file.
		await import("/uxasset/externals/snc-wds-user-cards/index.jsdbx"); 

	})();

}

Yes, it really is as simple as that! Now, within the HTML of my widget I can use any of the components in that project like so:

<div>
	<snc-wds-user-card-full 
		title="About me"
		is-vip="true"
		is-escalated="true"
		name="Dylan Lindgren"
		position="Advisory Solution Developer"
		company="ServiceNow"
		mobile-phone="+81 123 456 789"
		business-phone="+81 987 654 321"
		email="dylan.lindgren@servicenow.com"
		address="129 W 81st St, New York, NY 10024, United States"
		initials="DL"
		avatar-url="https://en.gravatar.com/userimage/5790819/e78c3a3ec75eadf7e677183d28732b0d.jpeg"
		address-name="Work address"/>
</div>

And when I use that widget on a portal page, the component appears exactly as it does in Next Experience.

The new widget made up of a Next Experience component, used a tab in a Standard Ticket page on Service Portal

Next Steps

NOTE: A follow up article has been posted addressing all of the questions raised in this section.

So while this process allows us to include the component inside a widget, and to pass values in to the component via its attributes, there are still a few things that are unclear and I need to do further research on.

Firstly, in my example “user card” component I’m passing in text values through its attributes, and each individual thing on the interface is controlled by a single attribute. However, a lot of components accept JavaScript objects as their properties, and I’m wondering what the method would be to achieve that.

Secondly, this component doesn’t have any actions you can perform on it. However if it did, how would one handle to those actions from the widget? For example, if my “user card” had a button on it that fired an event, in UI Builder you could handle that with an event binding (e.g. to redirect to a different page). There’s no concept of event binding in Service Portal though, so instead I’m assuming somewhere in the widget’s code that exact event would need to be listened for and handled there.