スキンUI API

基本スキン(basic-v2)にメニュー・ダイアログ・領域・装飾を追加するroom.skin APIの全一覧です。

最終更新 2026年10月19日

このページ

room.skin を使うと、基本スキン(basic-v2)の画面にボタン・メニュー・ダイアログ・領域を追加したり、ニックネームやメッセージの表示を変えたりできます。このページは正式な一覧です。初めての方はスキンUIを拡張するからご覧ください。

レガシースキン(basic)にはこのAPIはありません。レガシースキンについてはレガシースキンAPIをご覧ください。

共通ルール

U.chat('*').on('after.create#my-ui', function (room) {
	if (room.id !== 'my-room') return;
	var ui = room.skin;
	var remove = ui.menu.add({
		id: 'hello',
		label: 'あいさつ',
		onSelect: function (ctx) { ctx.room.action.send('こんにちは!'); },
	});
	// 不要になったら remove();
});
  • 登録のタイミング: after.create の中で登録します。チャットルームを設置し直すと(room.reload()、タグの再挿入)、スキンの登録はすべて消え、after.create が再度届きます。このとき、そのルームだけに登録したイベント(U.chat('my-room').on)も消えるため、上の例のように U.chat('*') に登録して room.id で絞り込むと、設置し直すたびに自動で再登録されます。
  • ID: 登録ごとに id が必要で、同じ種類の中で重複するとエラーを投げます。
  • 解除関数: add 系の関数は解除関数を返します。最初に呼ぶと true、その後は false を返し、何度呼んでも安全です。
  • 同期コールバックのみ: condition、describe、resolve、match などのコールバックは同期関数にしてください。Promiseを返すとエラーとして扱われ、その項目は除外されます。コールバック内の例外はコンソールに記録され、その項目だけがスキップされます。onSelect は戻り値を見ないので非同期でも構いませんが、その中の例外は自分で処理してください。
  • 表示だけが変わる: メニューを隠したり装飾したりしても権限は変わりません。権限のチェックはサーバーが行います。
  • チャットルームが破棄された後に room.skin を呼ぶとエラーを投げます。
API 位置
ui.menu 入力欄ツールバーのボタン
ui.userMenu ニックネームを押したときに出るメニュー
関数 戻り値 説明
add(item) 解除関数 項目を追加
remove(id) true/false 項目を削除。存在しないIDなら false
resolver.add({ id, resolve }) 解除関数 項目一覧を調整。下のメニューresolverを参照
resolver.remove(id) true/false resolverを削除
resolver.refresh() — 条件が変わったときに一覧を再計算

項目のフィールド

キー 形式 説明
id 文字列 必須。固有のID
label 文字列 表示テキスト。なければ title、それもなければ id
title 文字列 マウスを重ねたときの説明
order 数値 小さいほど前。既定は0
group 文字列 userMenu: 同じグループの項目を1行にまとめます
column 0/1 userMenu: 同じグループ内で左(0)・右(1)の2列に分けます
separator 真偽値 userMenu: 区切り線。選択できません
disabled 真偽値 無効(表示されるが押せない)
pressed 真偽値 menu: 押された状態で表示(オン・オフボタン)
padding 'none'/'normal' menu: ボタンの内側の余白。既定は 'normal'
condition(ctx) 関数 false を返すと非表示
describe(ctx) 関数 その都度変わるフィールド(label、disabled、pressed など)をオブジェクトで返します。null なら非表示
onSelect(ctx) 関数 押されたとき

コールバックのctx

API ctx
ui.menu { room, skin }、onSelect では event も
ui.userMenu { room, skin, target, messageUid, message, event } — target は押された人のユーザーオブジェクト。メッセージのニックネームを押した場合は messageUid と message が入ります
ui.userMenu.add({
	id: 'profile',
	label: 'プロフィールを見る',
	condition: function (ctx) { return !!ctx.target.id; },
	onSelect: function (ctx) {
		window.open('/profile/' + encodeURIComponent(ctx.target.id));
	},
});

既定の項目

API ID(order)
ui.menu skin.bold(-60), skin.italic(-50), skin.underline(-40), skin.color(-30), skin.emoticon(-20), skin.upload(-10), skin.brand(100), skin.scroll(110)
ui.userMenu skin.whisper、skin.mute、skin.ban のように skin. で始まります。order は -1000から10刻み

resolverはすでに登録された項目だけを扱います。非表示にする、順序を変える、表示値を変える、無効にすることができ、新しい項目を作ったり無効な項目を有効にしたりすることはできません。

ui.userMenu.resolver.add({
	id: 'hide-ignore',
	resolve: function (ctx) {
		return ctx.current.filter(function (item) { return item.id !== 'skin.ignore'; });
	},
});
項目 説明
resolve(ctx) ctx はメニューのctxに base(resolver適用前の一覧)、current(前のresolverまで適用した一覧)を加えたもの。配列を返すとその一覧に置き換え、null ならそのままにします
返した配列 IDのない項目、登録されていないID、重複したIDは捨てられます。order で並べ直します

ダイアログ

関数 戻り値(Promiseの結果)
ui.dialog.alert(title, content) 確認 true、閉じる null
ui.dialog.confirm(title, content) 確認 true、キャンセル false
ui.dialog.prompt(title, content, value) 入力した文字列、キャンセル null
ui.dialog.password(title, content, value) 入力した文字列(伏せ字で入力)、キャンセル null
ui.dialog.select(title, content, options, value) 選んだ値(キー)、キャンセル null。options は { 値: '表示テキスト' } のオブジェクト
ui.dialog.open({ kind, title, content, options, value }) { id, result, close }
ui.dialog.confirm('挑戦', 'じゃんけんしますか?').then(function (ok) {
	if (ok) room.action.send('挑戦!');
});

var handle = ui.dialog.open({
	kind: 'confirm',
	title: '挑戦',
	content: '10秒以内に答えてください。',
	options: { backdropDismiss: false },
});
handle.result.then(function (ok) { /* true、false、または close に渡した値 */ });
setTimeout(function () { handle.close(null); }, 10000);
  • kind は alert、confirm、prompt、password、select のいずれかです。それ以外の値はエラーを投げます。
  • title、content はテキストとして表示します(HTMLではありません)。
  • options.backdropDismiss: false にすると、外側を押しても閉じません。
  • close(value) はその値で result を確定させ、true を返します。すでに閉じている場合は false です。
  • ダイアログは一度に1つずつ表示され、残りは順番に待ちます。スキン自体のダイアログが開いている場合は、そちらが先に表示されます。チャットルームが破棄されると、待っていたダイアログはすべて null で終わります。

領域の追加

ui.mount.* に mount(host, ctx) を渡すと、スキンが空の要素(host)を作って渡します。hostの中だけを扱い、外側のDOMは変更しないでください。

ui.mount.messageList({
	id: 'banner',
	position: 'before',
	mount: function (host, ctx) {
		host.textContent = '今日の20時にイベントがあります!';
		return function () { host.replaceChildren(); };
	},
});
関数 position 位置
header before(既定)、after ヘッダー領域の前後
headerTitle — チャットルームのタイトル部分の中
middle before(既定)、after 会話+ユーザー一覧領域の前後
messageList before(既定)、after 会話領域の前後
userList before(既定)、after ユーザー一覧の前後
composer above-input(既定、before-input も同じ)、after-input 入力欄の上、入力欄の後
footer before(既定)、after 入力領域の前後
wrap before(既定)、after、left、right チャットルーム全体の上・下・左・右
toolbar — 入力欄ツールバーの中(ボタンの後)
overlay — 画面の上に重ねる。下の重ねる領域を参照

すべて解除関数を返します。ui.mount.removeOverlay(id)、ui.mount.removeToolbar(id) でIDを指定して削除することもできます。サポートしていない position はエラーを投げます。

mountのctx

キー 説明
room, skin roomオブジェクト、room.skin
signal AbortSignal。後片付けの直前にabortされます。addEventListener(..., { signal }) に渡すと後片付けが自動になります
bounds() hostの getBoundingClientRect() の値
close() この登録全体を削除します(解除関数と同じ)
requestLayout() hostのサイズを変えた後、スキンに再配置を依頼
slot (領域)追加された位置の名前。例: messageList.before
layer, scope (overlay)重なりのレイヤーと範囲
message, author (message.extend)そのメッセージと送信者

mount が関数または { destroy } オブジェクトを返すと、hostがなくなるか登録を削除したときに一度呼ばれます。

重ねる領域

ui.mount.overlay({ id, layer, scope, exclusive, mount }) は、レイアウトを押し広げずに上に重ねます。

キー 値 説明
layer background-effect 背面の効果。クリックは通り抜けます
content-overlay(既定) 内容の上に情報を表示
modal 最前面で覆う
scope skin(既定) チャットルーム全体に重ねる
message-list 会話領域だけに重ねる
exclusive 真偽値 layer: 'modal' と一緒に使うと、この領域が表示されている間は ui.dialog のダイアログを表示せずに待たせます。scope が skin のときだけ使え、それ以外ではエラーを投げます
ui.mount.overlay({
	id: 'player',
	layer: 'content-overlay',
	scope: 'message-list',
	mount: function (host, ctx) {
		host.textContent = '再生中';
	},
});

固定お知らせ

関数 戻り値 説明
ui.topLayer.add({ id, content, backgroundColor, color, dismissLabel, weight }) 解除関数 会話領域の上部にあるお知らせ行に項目を追加します
ui.topLayer.remove(id) true/false 項目を削除
  • content は必須で、テキストとして表示します。
  • weight が大きいほど上に置かれます(既定は0)。
  • dismissLabel は、閲覧者がお知らせを閉じるボタンの文字です。
ui.topLayer.add({ id: 'event', content: 'イベント開催中!', backgroundColor: '#fff4cc', color: '#7a4b00' });

メッセージへの追加

ui.message.extend({ id, position, match, mount }) は、通常のメッセージとウィスパーの行ごとに領域を追加します。過去のメッセージと新しいメッセージの両方に適用されます。

キー 説明
position before(行の先頭、ニックネームの前)、inline(内容の直後)、after(既定、inline の後)
match(ctx) 追加するメッセージを選びます。ctx は { message, author, room, skin }。省略するとすべてのメッセージ
mount(host, ctx) mountのctx に message、author が加わります

message の主な値は kind('message' または 'whisper')、author(送信者)、content、uid、created、mine(自分が送った場合は true)です。ctx.close() はそのメッセージ1件ではなく、登録全体を削除します。

ui.message.extend({
	id: 'admin-badge',
	position: 'inline',
	match: function (ctx) { return ctx.author && ctx.author.auth >= 2; },
	mount: function (host) { host.textContent = ' [管理者]'; },
});

ニックネームの装飾

ui.nickname.resolver.add({ id, resolve })、remove(id)、refresh()。

項目 説明
resolve(ctx) の ctx { user, location, message, backgroundColor, room, skin, base, current }。location は 'message'(会話)または 'user-list'(ユーザー一覧)、message は会話のときだけ
返す値 { style, nickcon, iconsBefore, iconsAfter, addBefore, addAfter, tag, gradient, classes, vars } のうち変えるものだけ。null ならスキップします
style 下の使えるstyleを参照
gradient ニックネームの文字を左から右に塗る2〜8色の配列(例: ['#e65c00', '#d4145a'])。許可styleの色形式のみ受け付け、nullで消します。称号・アイコンには塗りません
classes ニックネーム全体([data-nickname-display])に付けるクラス名の配列。プラグインCSSで登録したルールを当てるのに使います。追加だけで(前のresolverのクラスは消せません)、最大16個。英字・数字・_・-だけの名前を受け付けます
vars ニックネーム全体に入れるCSS変数({ '--my-color': '#f00' })。人ごとに違う値をCSSに渡すときに使います。名前は -- で始め、値に ; { } があると捨てます。null でその変数を消します
nickcon { src, alt }(ニックネームの代わりに画像)または null(ニックコンを消す)
iconsBefore, iconsAfter [{ src, alt }]。ニックネームの前・後のアイコン一覧を丸ごと置き換えます。追加するには ctx.current.iconsAfter.concat(...)
addBefore, addAfter ニックネームの前・後ろに追加するパーツ [{ text, image, color, background, border, title, classes }]。片側最大6個、文字は16文字まで。classes(最大8個)でプラグインCSSの形を当てられます

画像の src には https://、http://、//、/ で始まるアドレスを使います。空白を含むアドレスや形式が正しくないアドレスは捨てられます。

ui.nickname.resolver.add({
	id: 'admin-nick',
	resolve: function (ctx) {
		if (!ctx.user || ctx.user.auth < 2) return null;
		return {
			style: { fontWeight: 'bold', color: '#c2410c' },
			iconsAfter: ctx.current.iconsAfter.concat({ src: 'https://example.com/star.png', alt: '管理者' }),
		};
	},
});

メッセージの装飾

ui.message.resolver.add({ id, resolve })、remove(id)、refresh()。通常のメッセージとウィスパーにだけ適用されます。

項目 説明
resolve(ctx) の ctx { message, author, backgroundColor, room, skin, base, current }。message は読み取り専用
返す値 { style, row, classes, vars } のうち変えるものだけ。null ならスキップします
style 内容の文字と行の背景。下の使えるstyleを参照
row.spacing 'normal' または 'relaxed'(行の余白を広げる)
row.hideNickname true ならニックネームを隠します。通常のメッセージにだけ適用され、ウィスパーでは隠しません
classes メッセージ1行全体に付けるクラス名の配列。プラグインCSSで登録したルールを当てます。追加だけで最大16個。本文の文字はその中の .message-content です
vars メッセージ行に入れるCSS変数({ '--my-accent': '#f00' })。ルールはニックネームの vars と同じです
ui.message.resolver.add({
	id: 'notice-highlight',
	resolve: function (ctx) {
		if (ctx.message.content.indexOf('お知らせ') < 0) return null;
		return { style: { backgroundColor: '#fff4cc' }, row: { spacing: 'relaxed' } };
	},
});

resolverは order(既定は0)の順、同じなら登録順に適用され、前の結果に上書きします。条件が変わって再計算が必要なら refresh() を呼んでください。

使えるstyle

ニックネーム・メッセージのresolverの style は、下のキーだけを受け付けます。それ以外のキーや形式が正しくない値は、何も知らせずに捨てられます。それ以外のCSSはプラグインCSSで登録し、ニックネームの classes で当ててください。

キー 使える値
color, backgroundColor #rgb, #rgba, #rrggbb, #rrggbbaa, rgb(), rgba(), hsl(), hsla()
fontWeight normal, bold, 100~900(100刻み)
fontStyle normal, italic, oblique
textDecoration none, underline, overline, line-through

プラグインCSS

ui.style.add({ id, css }) は解除関数を、ui.style.remove(id) は true/false を返します。

  • css の文字列をそのままチャットルーム画面の <style> として入れます。内容はチェックしません。プラグインがオフになるかスキンが片付けられると一緒に外れます。
  • このCSSはチャットルーム画面全体に効きます。ほかの部分に影響しないよう、クラス名の前にプラグイン名を付けてください。
  • ニックネームの文字は必ず [data-nickname-label] の中にあります。グラデーションを使うと同じ要素に [data-nickname-gradient] も付きます。
ui.style.add({
	id: 'myPlugin.flow',
	css: '.my-flow [data-nickname-gradient]{background-size:200% 100%;animation:my-flow 4s linear infinite}'
		+ '@keyframes my-flow{to{background-position:-200% 0}}',
});
ui.nickname.resolver.add({
	id: 'myPlugin.nick',
	resolve: function (ctx) {
		if (!ctx.user || ctx.user.auth < 2) return null;
		return { gradient: ['#538eff', '#f61ecf', '#538eff'], classes: ['my-flow'] };
	},
});

その他の機能

関数 戻り値 説明
ui.composer.guard.add({ id, shouldBlock, onBlocked }) 解除関数 入力欄の使用を止めます。shouldBlock(ctx) が真なら止めて onBlocked(ctx) を呼びます
ui.composer.guard.remove(id) true/false ガードを削除
ui.message.removeByUser(nick) 削除した件数 そのニックネームのメッセージを自分の画面から削除します
ui.scrollToBottom(force) true/false 会話の一番下へ移動。force がない場合、ユーザーがメッセージのニックネームやリンクにマウスを重ねているとき、または自動スクロールをオフにして上を見ているときは動かずに false

ガードの ctx は { action, draft, event, room, skin } で、action は 'send'(送信)または 'activate'(入力欄を押す、またはフォーカス)です。

ui.composer.guard.add({
	id: 'login-first',
	shouldBlock: function (ctx) { return ctx.room.my.auth < 1; },
	onBlocked: function (ctx) { ctx.skin.dialog.alert('ご案内', 'ログインした会員だけがチャットできます。'); },
});

読んでもよくわからない場合は お問い合わせ掲示板に質問を書き込んでください。

商号 UCHAT · 代表者 김경욱 · 事業者登録番号 141-05-32832
所在地 경기도 파주시 와석순환로 61 · 通信販売業届出番号 2013-경기파주-4485호
代表電話 010-8677-8633 · メール support@uchat.io

ⓒ 2013–2026 UCHAT. All rights reserved.