Decorate nicknames and messages

An example of changing nickname colors and images, message backgrounds, line spacing, and hiding nicknames in the default skin.

Last updated October 17, 2026

On this page

Instead of overriding CSS, the default skin (basic-v2) changes how nicknames and messages look through a defined mechanism (resolvers). It doesn't break when the skin changes, and scripts used together don't overwrite each other.

You can change the whole chat room's colors, font size, and look without code in the Skin menu of the admin page.

Code

This one block of code contains every decoration on this page. Replace the image URLs with your own images.

<script>U=window.U=window.U||{},U.events=U.events||[],U.chat=function(n){return{on:function(e,t){U.events.push([n,e,t])},off:function(e){for(var t=U.events.length;t>0;)U.events[--t][0]==n&&U.events[t][1]==e&&U.events.splice(t,1)}}};</script>
<script async src="https://client.uchat.io/uchat.js"></script>
<u-chat room="my-room" style="display:inline-block;width:100%;max-width:400px;height:500px"></u-chat>

<script>
U.chat('my-room').on('after.create#decorate', function (room) {
	var ui = room.skin;

	// 1. Moderator and admin nicknames: color and weight; admins get an image instead of the nickname
	ui.nickname.resolver.add({
		id: 'decorate.admin',
		resolve: function (c) {
			var auth = c.user ? Number(c.user.auth) : 0;
			if (auth < 2) return null;
			var patch = { style: { color: auth >= 3 ? '#e11d48' : '#2563eb', fontWeight: 'bold' } };
			if (auth >= 3) patch.nickcon = { src: 'https://example.com/img/owner-name.png', alt: c.user.nick };
			return patch;
		},
	});

	// 2. Level 10 and up: add a badge icon before the nickname (keep existing icons)
	ui.nickname.resolver.add({
		id: 'decorate.level',
		resolve: function (c) {
			if (!c.user || Number(c.user.level) < 10) return null;
			return {
				iconsBefore: c.current.iconsBefore.concat([
					{ src: 'https://example.com/img/badge.png', alt: 'Level 10' },
				]),
			};
		},
	});

	// 3. Messages that contain my name: background color and wider line spacing
	ui.message.resolver.add({
		id: 'decorate.mention',
		resolve: function (c) {
			var me = room.my.nick;
			if (!me || c.author.nick === me || c.message.content.indexOf(me) < 0) return null;
			return { style: { backgroundColor: '#fff4cc' }, row: { spacing: 'relaxed' } };
		},
	});

	// 4. Regular messages I sent: hide the nickname and change only the text color
	ui.message.resolver.add({
		id: 'decorate.mine',
		resolve: function (c) {
			if (!room.my.nick || c.author.nick !== room.my.nick) return null;
			return { style: { color: '#1d4ed8' }, row: { hideNickname: true } };
		},
	});

	// 5. Time sent (hh:mm) after the message
	ui.message.extend({
		id: 'decorate.time',
		position: 'after',
		mount: function (host, c) {
			host.textContent = ' ' + String(c.message.created || '').slice(11, 16);
			host.style.color = '#9ca3af';
			host.style.fontSize = '11px';
		},
	});
});

// Rules that use my nickname (3, 4) are recalculated after joining or a nickname change
function refreshDecorate(room) {
	room.skin.message.resolver.refresh();
}
U.chat('my-room').on('after.join#decorate', refreshDecorate);
U.chat('my-room').on('after.user.modi#decorate', refreshDecorate);
</script>

Nickname color and image

The resolve(c) of nickname.resolver.add is called every time a nickname is drawn. Return an object with only what you want to change, or null if there is nothing to change.

Value of c Description
c.user The nickname's owner (nick, auth, level, icons, nickcon, and so on)
c.location Where it is drawn. message for messages, user-list for the user list
c.current The result with earlier resolvers applied (style, nickcon, iconsBefore, iconsAfter)
c.base The default values before any resolver is applied
  • nickcon is an image shown instead of the nickname text (within 16px height). If the image fails to load, the nickname text is shown. nickcon: null also removes a nickcon received through member integration.
  • iconsBefore and iconsAfter replace the whole array. To keep existing icons, append to c.current.iconsBefore as in the code above.
  • Use image URLs that start with https://, http://, //, or /. URLs in other formats are ignored.

Message background and line spacing

The resolve(c) of message.resolver.add is called when drawing regular messages and whispers. You can read c.message (content, created, kind, and so on) and the sender c.author.

Return row: { spacing: 'relaxed' } to widen that line's padding so it stands out. The default is normal.

Hide the nickname on my messages

Return row: { hideNickname: true } and the nickname is not drawn on that line. This applies only to regular messages; whispers always show the nickname, because you need to know who sent them.

room.my.nick is empty before joining, so rules that use your nickname are recalculated in after.join with message.resolver.refresh(). If a nickname rule needs the same, call nickname.resolver.refresh().

Time next to messages

message.extend attaches a small area before (before), inside (inline), or after (after) each message, and lets you draw it yourself with mount(host, c). c.message.created is in YYYY-MM-DD HH:MM:SS format. If you also pass match(c), it is attached only to messages for which it returns true.

Available values

Target Key Value
Nickname and message style color, backgroundColor #rgb, #rgba, #rrggbb, #rrggbbaa, rgb(), rgba(), hsl(), hsla()
fontWeight normal, bold, 100–900
fontStyle normal, italic, oblique
textDecoration none, underline, overline, line-through
Nickname nickcon { src, alt } or null
iconsBefore, iconsAfter [{ src, alt }]
Message row.spacing normal, relaxed
row.hideNickname true, false

Any other CSS properties or values, and HTML, are silently ignored. If you need a freer look, draw it yourself inside the area you get from message.extend or mount.*.

Things to note

  • resolve and match must be synchronous. Returning a Promise is treated as an error and that rule is ignored.
  • With several resolvers, they are applied on top of each other in order of their order value (registration order when equal). Later rules overwrite the same keys.
  • add returns a remove function. To turn a decoration off, call that function or call remove(id). For the full list, see Skin UI API.
  • This API exists only in the default skin (basic-v2).

Still not sure how it works? Ask your question on the contact board.

Business name UCHAT · CEO 김경욱 · Business registration no. 141-05-32832
Address 경기도 파주시 와석순환로 61 · Mail-order business registration no. 2013-경기파주-4485호
Phone 010-8677-8633 · Email support@uchat.io

ⓒ 2013–2026 UCHAT. All rights reserved.