初めに
本来もっと考えないといけないことがあるのですが現実逃避的に色々な検証をしています。
今回はその1つとしてワークスペースのフォームフィールドでヘルプの出し方を調べてみたのでここにまとめます。
PDI環境
試したPDI環境はこんな感じです。
Version: Zurich

準備
いつものようにこれように適当にワークスペース用のアプリを作成します。

テーブルを作成したら適当にフィールドを作っておきます。
・TextField:String型
・ChoiceField:Choice型
・HtmlField:HTML
・DateField:Date
・DateTimeField:DateTime
・RefereceField:Reference(sys_user)
・List RefereceField:List/Reference(sys_user)
アノテーション
フォーム注釈(アノテーション)はCSAとかの勉強してるとヘルプとかフィールドの説明をしたい時、最もはじめに考えるべきコンポーネントと言われています。
個人的にはフィールドメッセージの方が短文だとフィールド下部に来てわかりやすいのですが、実装の簡単さでいうとこちらが勝つのかなという所です。
アノテーションのいいところはHTMLも効くところです。
例えば、下のようにrich textでHTMLコードを書くとHyperLinkでのヘルプが可能となります。
<p><a title="HyperLink" href="https://qiita.com/" target="_blank" rel="noopener">HyperLinkだお</a></p>
また、多言語対応も一応出来る?らしいので試してみます。
フォーム注釈に複数の言語をサポートする
ServiceNow 動的アノテーション – アノテーションでの JavaScript の使用
PDIに日本語を入れていなかったので英語だけですが、sys_ui_messageを追加します。

Annotation TypeをTextにして、gs.getMessageしてみます。

プラットフォームを見てみるとgs.getMessageが効いているように見えます。
現時点(2026年2月)ではワークスペースでアノテーションを利用して多言語対応が難しいのかもしれないです。

ツールチップ/ヘルプテキスト(help tips)
次にツールチップ/ヘルプテキストを試してみます。
対象フィールドを選択し、Advanced viewから関連リストのLabelsを更に選択します。

同じように他のフィールドにも適用します。
ワークスぺースで確認する前に個人設定からDisplay > Show help tips on formsを有効にしておきます。
これをしておかないとhintは出ません。
hintを登録したフィールドラベルの隣にアイコンが出てきて、クリックする事でhintを表示する事が出来ます。

このヒントは言語ラベル毎に設定する事で簡単に多言語対応が出来そうですが、スクリプトやHTMLについて確認する限りでは使用できないみたいです。
また、上述の通り、個人設定を有効化しておかないと表示されないのでユーザーに必ず見てほしいヘルプについては別の方法を選択した方がいいかもしれません。
フィールドメッセージ
次にフィールドメッセージを試してみます。
OnLoadのClientScriptを作成して、各フィールドにメッセージを出します。
スクリプトはこんな感じです。
function getMessageWrap(messageKey) {
var ret = getMessage(messageKey);
console.log(ret);
if(ret === messageKey)
ret = getMessage(messageKey);
console.log(ret);
return ret;
}
function onLoad() {
//Type appropriate comment here, and begin script below
g_form.showFieldMsg("textfield", "フィールドメッセージだお");
g_form.showFieldMsg("choicefield", "チョイスです", false);
g_form.showFieldMsg("htmlfield", "htmlfieldメッセージだお");
g_form.showFieldMsg("datefield", "datefield");
g_form.showFieldMsg("datetilefield", "datetilefieldだお");
g_form.showFieldMsg("referencefield", getMessageWrap("HelpText"));
g_form.showFieldMsg("listreferencefield", "<p>AAAA</p>");
}
getMessageWrapを作っているのはたまにgetMessageがkeyを稀にですがそのまま返すことがあるからです。その対策にgetMessage関数の戻り値とkeyが一致していたら再度呼び出すようにしています。
クライアントスクリプト関数 getMessage() が、Service Portal およびワークスペースで予期される翻訳済みテキストを返さない
全部infoにしていますが見た目はこんな感じです。

残念ながらHTMLは使えないようです。多言語対応はgetMessageでやりやすいですが、ハイパーリンクなどの埋め込みは難しいみたいです。また、2026/2/3時点のZurichではワークスペースでフィールドメッセージを利用するとフィールドの値を変更してフォーカスを外すとフィールドメッセージが消えるバグが存在しています。。。

これに文字を入力してフォーカスを外すと下側のメッセージが消えます。
フィールドデコレーター(Client Script/Server Script)
コミュニティを見ているとワークスペースのTooltipやHintでよく候補としてあげられているフィールドデコレーター(FieldDecorator)を試してみます。
Studioからだとうまくいかないのでプラットフォームから作成します。

Field Decoratorを作成して、スクリプトはClient Scriptにしておきます。

上記を追加するとTextField内に指定したアイコンが追加されている事を確認できます。

※Tooltipを指定しているとホバーする事で表示できます。
Field Decoratorアイコンをクリックする事でメッセージが表示できます。
これの利点はHTMLを使えるところでしょうか。
Tooltipプロパティの多言語対応が難しそうですが、getMessageも使えるので多言語対応をしやすいですし、フィールドメッセージを表示する事も可能です。
ただし、フィールドデコレーターはかなり扱いやすいですがChoiceやHTMLフィールド等の一部のタイプでは利用出来ないので注意が必要です。
function onClick() {
var link = '<a href="https://qiita.com/mototoke">Mypage</a>';
var message = getMessage("HelpText") + ' ' + link + ' ';
g_form.addInfoMessage(message);
}
Server Scriptでも良いですが、再描画が発生する関係からなのか分からないですが新規作成レコードだとエラーが発生します。
var link = '<a href="https://qiita.com/mototoke">Mypage</a>';
var message = gs.getMessage("HelpText") + ' ' + link + ' ';
gs.addInfoMessage(message);
Client Script、Server Script両方で読み取り専用にしてもクリックが可能のようです。

フィールドデコレーター + g_modal
正直、addInfoMessageくらいで十分だと思いますが、より丁寧にヘルプを出したり長文を出す必要があるのであればこういった事も可能です。
function onClick() {
g_modal.alert(
'これはヘルプテキストです.',
"めちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章です",
() => {},
{
"buttonTitle": "読みました",
"buttonType": "primary"
}
);
}
文章が長ければ自動的にスクロールもつけてくれるので便利ですね。
ハイパーリンクつけたい等あればボタンは二つ出てしまいますが、richTextを使うこともできます。
function onClick() {
g_modal.richText(
'これはヘルプテキストです.',
`<p>TEST</p>
<br />
<p><a title="HyperLink" href="https://qiita.com/" target="_blank" rel="noopener">HyperLinkだお</a></p>
`,
() => {},
{
"cancelTitle": "閉じる",
"confirmTitle": "読みました",
"cancelType": "default ",
"confirmType": "confirm"
}
);
}
フィールドデコレーター + UI Page
g_modalでも良いですが、見た目にこだわるならUI Pageを使うことも可能です。
今回はこだわらないですが簡単なUI Pageを作成して呼び出してみます。
簡単と言いつつjelly構文には慣れていないのでかなり時間がかかりました。(´・ω・`)悲しみ
- 呼び出すUI Page
<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
<!-- message key を取得 -->
<g:evaluate var="jvar_message_key" expression="jelly.sysparm_message_key || RP.getWindowProperties().get('sysparm_message_key')" jelly="true"/>
<!-- message を取得 -->
<g:evaluate var="jvar_message" jelly="true">
var key = jelly.sysparm_message_key;
var message = gs.getMessage(key);
message = (message !== key) ? message : '';
<!-- 最後に変数を評価する事でjvar_messageに代入される -->
message;
</g:evaluate>
<div style="white-space:pre-line">
<!-- message が存在する場合(jvar_messageが空じゃない) -->
<j:if test="${!empty jvar_message}">
<div style="white-space:pre-wrap;">
${jvar_message}
</div>
</j:if>
<!-- message が空の場合 -->
<j:if test="${empty jvar_message}">
<div style="white-space:pre-wrap;">
メッセージが見つかりませんでした。
</div>
</j:if>
</div>
</j:jelly>
本来はちゃんとロールつけるべきですが、PDI環境なのでadminで。

宣言アクションを以下のように修正します。
- 呼び出し側
function onClick() {
g_modal.showFrame({
title: 'ヘルプなんですわ',
url: '/x_1603370_helptest_Test Help UI Page.do?' + [
'sysparm_message_key=' + "HelpText",
].join('&'),
height: '300px',
width: '400px',
hasLoadingMessage: true,
});
}
PDIだからなのかわかりませんが、若干Loadingが長いですが、こんな感じで表示ができます。

フィールドデコレーター(UXF Client)
使った事がないので今回初めて触るのですが、
UXF Clientを利用しても同じような事が出来そうです。
今回やってみた感想として実装までの道のりがややこしく使いこなすには相当時間がかかりそうという印象です。
正直なところ、実際に触ってみてもリソース同士のつながりはまだ完全には理解できていません💦
最初に結論を書いておきます。
UXF Client(Declarative Action → UI Builder Modal)で
payload(title / message)を表示する場合、
payloadをModal コンポーネント内で直接参照は難しそう
※もしかしたらやり方があるのかもしれませんが私にはわかりませんでした💦
その為、今回は
event.payload → client state parameter に格納
state を Label / TextArea から参照
という構成でモーダル表示を実現しました
以下はその検証過程と実装例です。
最初に呼び出すモーダルをUIBuilderで作成します。
Recordの該当Viewを開きます。
ここでなぜかStudioのUIBuilderからもPlatformのUIBuilderからも対象のスコープが選べませんでした。

同様の問題になっている人が結構いるみたいです。
UI ビルダーでのスコープアクセス
UI ビルダーのスコープアクセス制限
仕方がないのでPluginsからinstall済みのUI BuilderをRepairしてみます。

上記の対応でスコープが選択できるようになりました\(^_^)/

本筋からそれましたが、ここでやりたかった事はmodal画面の作成です。
Content > ModalsのAdd newでCustomを選択します。
実際には用途に応じて使い分けが必要になると思います。

作成したModals > AlertをRenameしておきます。
Modalの外観を作成します。
Header:Label Value
Body:TextArea
Footer:Button
をそれぞれ配置します。

ButtonのEventsにAdd handlerでOpen or close modal dialogを設定しておきます。

次にBodyを選択してEventsにあるHandled eventsを作成します。

Event LabelはHelp Text Modal eventにして、Payload fieldsにtitleとmessageをstringで追加しておきます。

イベントを作成したら上側のAdd event mappingから作成したHelp Text Modal eventを選択します。


その次にhandlerでOpen or close modal dialogを選択します。

ひとまずUIBuilder側の準備がこれで完了です。
次にプラットフォームから新しいDeclative Actionを作成します。

Action Payload Definitionsの定義も必要なのでこの画面から新規作成します。

{
"type": "MAP_CONTAINER",
"container": {
"title": {
"type": "EVENT_PAYLOAD_BINDING",
"binding": {
"address": ["title"]
}
},
"message": {
"type": "EVENT_PAYLOAD_BINDING",
"binding": {
"address": ["message"]
}
}
}
}
次にAction Assingmentの関連リストにあるAction Model Fieldsで新規作成します。

あまりよくわかっていないですがNOW Developer 5.2曰く
この変数同士がつながるようです?

次に、Action Assignment のタブでUX Add-on Event Mappings を開きます。

今一つ結びつきがわかっていないのですが、Action Payload Definitionで定義したPayloadをコピーしてUX Add-on Event MappingのTarget Payload Mappingにペーストしないといけないようです。

ここまで来たらワークスペースの画面にあるアイコンからモーダルが開くことを確認できました。(...長かった)

なぜかCloseも動いていないのでボタンを押したらモーダルが閉じるようにするのと
TitleとMessageを渡して表示が出来れば良さそうです。
閉じない原因はすぐにわかりました。
ボタンのイベントでOpen modal dialogにチェックを入れていたのでこれを外すだけで良かったです。

ただここからがどうやってUIBuilder側に値を渡せるのか、Modalのlabelとtextareaに変数を表示できるのか不明でした。
一旦、payloadの定義を書き換えて静的に渡すことが出来ているのか試すことにしました。
Action Payload DefinitionのPayloadとUX Add-on Event MappingのTarget Payload Mappingを下記のようにします。


UIBuilderを色々見てたらeventのpayloadにmessageとtitleがあるのを発見しました。
そこで実際に値が来ているのかconsoleに表示して確かめてみました。

コンソールログを見てみると確かに値はUIBuilder側に来ていそうです。

そうなるとeventが受け取っているpayloadをどうやって参照するかになってくるのですが、何となくModal Openのhandlerだけでは無理そうだと思いました。
その為、ここでeventのmappingを修正します。
元々、event mappingで定義していたOpen or close modal dialogを1度削除します。

次にClient stete parametersを定義します。
titleとmessageを定義して閉じます。

再度、Add event mappingをクリックし、Help Text Modal eventを選択します。

Bind DataにEvent payloadにあるtitleを指定します。

同じようにmessageもAdd event mappingでHelp Text Modal eventにつなげておきます。
ここで再度、Add event mappingでHelp Text Modal eventとOpen or close modal dialogを定義しなおします。
1度削除したのは何となくイベントの順番が作成した順番になるんじゃないかと思ったからです。
3つ定義出来たら以下のようになります。

Modalのlabelとtextareaはそれぞれのvalueにclient state parameterを参照するようにしておきます。


これでUIBuilderを保存して、ワークスペースでフィールドデコレーターをクリックすると

一応、Payloadで定義していたタイトルとメッセージを表示する事が出来ました。
もっとうまいことすれば動的に内容を変更して表示もできるのかもしれないですが、今の私のレベルでは難しいのとそろそろ力尽きてきたのでここらへんにしておきます。
おわりに
今回はワークスペースで色々なヘルプの出し方を調べてみました。
この記事の内容をChatgpt君がわかりやすくまとめてくれました。
| 方法 | 表示位置 | HTML | 多言語対応 | ユーザー操作 | Workspace向き | 備考 |
|---|---|---|---|---|---|---|
| フォーム注釈(アノテーション) | フィールド周辺 / 上部 | ✅ | △(Workspaceでは制限あり) | 常時表示 | ○ | 実装が最も簡単。Workspaceでは gs.getMessage() が効かないケースあり |
| ツールチップ / ヘルプテキスト(Hint) | ラベル横アイコン | ❌ | ✅ | クリック | ○ | 個人設定「Show help tips」が必要 |
| フィールドメッセージ | フィールド下部 | ❌ | ✅ | 常時表示 | △ | Zurich時点で入力後に消える不具合あり |
| フィールドデコレーター(Client Script) | フィールド横アイコン | ✅ | ✅ | クリック | ◎ | 最も柔軟。Choice / HTML フィールドでは使用不可 |
| フィールドデコレーター(Server Script) | フィールド横アイコン | ✅ | △ | クリック | △ | 新規レコード時にエラーが出ることあり |
| フィールドデコレーター + g_modal | モーダル | △(テキスト中心) | ✅ | クリック | ◎ | 長文・スクロール対応が楽 |
| フィールドデコレーター + UI Page | モーダル | ✅ | ✅ | クリック | ◎ | 見た目自由度最大。実装コスト高 |
| フィールドデコレーター(UXF Client) | フィールド横アイコン | △ | △ | クリック | ◎ | 情報が少ない。手順がかなり複雑。実装コスト高。 |
個人的な所感をまとめるとこんな感じでしょうか。
-
個人的な所感(まとめ)
- 短文・常時見せたい説明
→ フォーム注釈 / フィールドメッセージ
- 短文・常時見せたい説明
-
ユーザーが必要な時だけ確認するヘルプ
- → フィールドデコレーター
-
長文・HTML・リンク必須
- → フィールドデコレーター + g_modal / UI Page
-
将来性・Workspaceネイティブ重視
- → UXF Client
「これが唯一の正解」という方法はなく、
「どれくらい見せたいか」 「どれくらい凝りたいか」 「ユーザーにとって必須 or 任意」等で使い分けるのが現実的だと感じました。
Servicenowで何かをやろうとするとやり方が色々あったり、プラットフォームとワークスペースで出来る事と出来ないことが違ったり、そもそもの情報が少なかったりと思っていたよりも時間がかかってしまいました。
ですが実際に触れる事で色々分かった事もあったので良かったと思います。
拙い記事ですがどなたかの参考になれば幸いです。
UXF Client周り誰かわかりやすい解説記事書いてくれないかなぁ
参考URL
以下のURLを参考にしました。有益なサイト達に感謝します。
ServiceNow 動的アノテーション – アノテーションでの JavaScript の使用
フォーム注釈に複数の言語をサポートする
Support field hints in Workspace
クライアントスクリプト関数 getMessage() が、Service Portal およびワークスペースで予期される翻訳済みテキストを返さない
情報メッセージにハイパーリンクを追加する方法
UXF Client Declarative Action Create | UI Builder Day 16
[E17] You & I Builder Live! Field Decorator Declarative Actions
UIB: UI Action to initiate Modal Dialog created in UI Builder
UI ビルダー でのモーダルの作成
コンポーネントへのモーダルの追加
Opening a modal from Configurable Workspaces (Next Experience / UI Builder / Declarative Actions)
Opening a modal from a record in Configurable Workspaces
ServiceNow の宣言型アクション:完全ガイド
Using event payloads in UI Builder
UI ビルダーのイベントペイロード




























