Style migration guides
Changes to style templates and APIs across Textual 5, 6, and 7.
A reference from an earlier chapter
This material preserves the original Textual documentation and may describe older versions, former services, or superseded policies. It is not a statement of current availability or new Blendbyte commitments.
On this page
Style Developers: Migrating to 6.0.0
Introduction
For a style to be fully compatible with Textual 6, some changes are required.
This knowledge base article describes these changes.
Templates
Changes have been made to the following template files:
If a style overrides any of these template files, then please patch each file.
Click each file to view the difference between Textual 5 and Textual 6.
Conversation Tracking
To reduce clutter, Textual now has a built-in implementation of the conversation tracking feature.
The following functions no longer need to exist in a style's scripts.js file:
-
updateNicknameAssociatedWithNewMessage()
-
toggleSelectionStatusForNicknameInsideElement()
-
userNicknameSingleClickEvent()
Replacements
Parts of the file that callout to updateNicknameAssociatedWithNewMessage() can be replaced by ConversationTracking.updateNicknameWithNewMessage(), which takes the same arguments
Parts of the file that callout to userNicknameSingleClickEvent() can be replaced by ConversationTracking.nicknameSingleClickEventCallback(), which takes the same arguments
Example
Textual.newMessagePostedToView = function(line)
{
var element = document.getElementById("line-" + line);
ConversationTracking.updateNicknameWithNewMessage(element);
}
Textual.nicknameSingleClicked = function(e)
{
ConversationTracking.nicknameSingleClickEventCallback(e);
}
Compatibility
Some styles, such as those that modify the layout of the DOM, will not be compatible with Textual's implementation of the conversation tracking feature. Those styles must implement their own logic for this feature.
Loading History
When a user clicks into a view for the first time, Textual loads their history from the previous session. It is recommended that a style fades in the history when it finishes loading, instead of having it appear suddenly.
To achieve this effect, set the opacity of the #historic_messages element to zero (0), which will hide this element by default. Set a transition on opacity changes, then change the opacity of this element when the history finishes loading.
To make this as easy as possible, the class .loaded is automatically added to the #historic_messages element when the history finishes loading.
Example
#historic_messages {
transition: opacity 0.8s ease-in;
opacity: 0;
height: 0;
margin: 0;
padding: 0;
}
#historic_messages.loaded {
opacity: 0.6;
height: auto;
}
Alternatives
The callback Textual.viewFinishedLoadingHistory() is invoked when the history finishes loading. A style can use this callback to perform other transitions.
Custom Scrollbars for Dark Styles
Textual now adds the attribute customscroller=true to the <body> element when the user has macOS setup to always show scrollbars.
It is recommended that a styles with dark background setup a custom scrollbar appearance when this attribute is set so that the user does not see a white scrollbar on a dark background.
To make this task easier for style authors, the following code can be pasted into a style'sdesign.css file. This code creates a scrollbar which appears similar to the normal OS X scrollbar, but darker.
body[customscroller="true"]::-webkit-scrollbar {
width: 17px;
}
body[customscroller="true"]::-webkit-scrollbar:horizontal {
height: 0;
}
body[customscroller="true"]::-webkit-scrollbar-track {
background: #393939;
box-shadow: inset 1px 0px 0px 0px #4b4b4b;
}
body[customscroller="true"]::-webkit-scrollbar-thumb {
background-color: #7c7c7c;
border: 4px solid transparent;
border-left: 5px solid transparent;
border-radius: 20px;
background-clip: content-box;
}
body[customscroller="true"]::-webkit-scrollbar-thumb:hover {
background-color: #b0b0b0;
}
Overlay Color
Textual 6 allows users to view multiple channels at once. When a user is viewing multiple channels, a transparent view is laid on top of each channel except the frontmost one.
A style can change the color of this view in its styleSettings.plist file by defining a string value for the key named Channel View Overlay Color.
Hexadecimal notation, in RRGGBBAA order, is the only format supported by this setting.
Example
<key>Channel View Overlay Color</key>
<string>#00000066</string>
In this example, #00000066 produces the color black with 40% alpha.
app Object
The app object now uses callback functions instead of return values.
Example
app.inlineImagesEnabledForView(
function(returnValue) {
console.log(returnValue);
}
);
Style Developers: Migrating to 7.0.3
Introduction
For a style to be fully compatible with version 7.0.3, some changes are required. This knowledge base article describes these changes.
baseLayout.mustache Template
Changes have been made to the baseLayout.mustache template file. If a style overrides this template file, then the changes made to this file must also be applied to that overridden by the style.
baseLayout.css
CSS properties that should be consistent between all styles has been moved to a separate file named baseLayout.css which is now imported by baseLayout.mustache. Do not override baseLayout.css.
Addition of message_buffer container
The #message_buffer container is used by the new dynamic buffer feature to house messages that it maintains. Without this container, no messages will appear for the user because there is nowhere to place them.
Removal of historic_message container
The #historic_messages container has been removed. Messages from the previous session are now placed in the #message_buffer container with no distinguishable characteristics.
Message Buffer Session Indicator
The dynamic buffer inserts a marker stylized with the class .message_buffer_session_indicator to allow the user to distinguish which session a section of the scrollback is from.
A style can modify the properties of this class or replace the contents of the messageBufferSessionIndicator.mustache template to change the appearance of this marker.
Example Appearance
Example Appearance Properties
/* Message buffer session indicator */
.message_buffer_session_indicator {
display: flex;
display: -webkit-flex;
padding: 0.5em 0;
}
.message_buffer_session_indicator > hr {
background: #dbdbdb;
border: 0;
height: 1px;
margin-top: 0.6em;
flex: 1;
-webkit-flex: 1;
}
.message_buffer_session_indicator > span {
font-style: oblique;
margin: 0 1em;
color: #a6a6a6;
}
.message_buffer_session_indicator + #mark {
display: none;
}
Dynamic Buffer
The new dynamic buffer feature removes messages from the top or bottom of the scrollback, depending on scroller position, when the number of visible messages exceeds an undocumented limit. A style should be designed with the understanding that there is no guarantee a particular message will be visible in the scrollback because of this.
If a style wants to keep a copy of a particular message so that it is not removed, then that message should be moved outside of the #message_buffer container.
Dynamic Buffer — core.js Changes
Message Added
The Textual.newMessagePostedToView(lineNumber) callback is now deprecated. It will be called if present, but it is preferred that you use Textual.messageAddedToView(lineNumber, fromBuffer) instead.
The second argument of the Textual.messageAddedToView callback is true when the message was restored by the dynamic buffer when the user scrolls towards it.
Message Removed
Added Textual.messageRemovedFromView(lineNumber) callback which is called when a message is removed by the dynamic buffer.
Other Changes
Some functions declared by the Textual object have moved. These functions were out of the scope of core.js to begin with which means this change should not break a custom style unless it was doing naughty things.
Scrolling Changes
The automatic scroller no longer uses a timer to detect when the height of the document changes. Instead, it is told when HTML will be added to or removed from the document.
If a custom style adds or removes HTML through the use of JavaScript, then it will need to tell the automatic scroller before it does so, so that the document can be automatically scrolled.
To accomplish this, call the prototype function prepareForMutation() on any element prior to modifying it.
You only need to call prepareForMutation() once within a synchronous block of code (such as a function).
The automatic scroller will not scroll until the block of code completes.
Example
document.body.prepareForMutation();
document.body.firstChild.remove();
Style Developers: Migrating to 7.0.7
Introduction
For a style to be fully compatible with version 7.0.7, some changes are required. This knowledge base article describes these changes.
Templates
New Template Engine Version
To encourage style authors to adapt the newest features of Textual 7, the template engine version has changed.
To advertise support for the new template engine version, edit the style's styleSettings.plist file.
Modify the Template Engine Versions setting to include version 4.
Example
<key>Template Engine Versions</key>
<dict>
<key>default</key>
<integer>4</integer>
</dict>
New Attributes
Added data-appearance attribute to <body> which is either “dark” or “light”. The value of this attribute is automatically calculated based on the background color of the style.
Renamed Attributes
Nearly all custom attributes have been renamed to provide greater consistency and easier access through JavaScript. Below is a table of all attributes that have been renamed.
| Old Name | New Name |
|---|---|
| bgcolor-number | data-background-color |
| channelname | data-view-name |
| color-number | data-foreground-color |
| coloroverride | data-override-color |
| command | data-command |
| customscroller | data-custom-scroller |
| highlight | data-highlight |
| ltype | data-line-type |
| mtype | data-member-type |
| selected | data-selected |
| systemversion | data-system-version |
| timestamp | data-timestamp |
| viewtype | data-view-type |
Attribute Placement
All custom attributes that appeared in <html> have moved to <body>.
Nickname Colors
The logic that determines which color is assigned to a nickname has changed. Nicknames are now assigned a consistent, unique color instead of picking from a pool of thirty possibilities.
Color Values
The new nickname colors are literal RGB or HSL values. For example: hsl(293, 81%, 69%)
Templates
When rendering each template, the color of each nickname is set using a the style attribute.
A custom attribute (formally colornumber) is no longer used to set the color in a rendered template.
It is possible for a custom color to be assigned to a nickname using the setcolor command. To provide a style more context, the attribute data-override-color is added to a nickname when a custom color is set.
Variations In Color
The shade of colors assigned will vary depending on whether a style has a light background or dark background. A light background will produce colors that are slightly darker whereas a dark background will produce the opposite.
A style's Underlying Window Color setting is used to infer which shade of colors to assign.
Optionally, a setting named Nickname Color Style can be set. This setting instructs Textual to use a specific shade of colors, regardless of the style's background.
Possible values:
-
HSL-light — colors that are better suited for a light background.
-
HSL-dark — colors that are better suited for a dark background.
Example
<key>Nickname Color Style</key>
<string>HSL-dark</string>
Inline Media
Textual is now capable of showing more than images inline with chat.
Styling
Each type of media that is shown inline with chat can be customized by adding rules to its CSS selector. Selectors follow a common format: they begin with “inline” and a descriptor follows.
Examples
.inlineImage
.inlineVideo
.inlineGfycat
.inlineTwitchClips
.inlineTwitchLive
.inlineVimeo
.inlineYouTube
This list contains example selectors. This list is incomplete.
Style Developers: Migrating to 5.1.2
Off-the-Record Messaging (OTR)
The line type off-the-record-encryption-status has been added.
Style this line type so that it immediately grabs the user's attention when it appears.
For example:
/* off-the-record-encryption-status Message Event */
body div.line[ltype="off-the-record-encryption-status"] .message {
color: #ff0000;
font-weight: 700;
}
Other Changes
The line type dccfiletransfer has been renamed to dcc-file-transfer.
Style Developers: Migrating to 5.1.4
Improved Scroll Performance
Historic messages are now placed inside the container named “historic_messages,” which is a child of “body_home”
Style the “historic_messages” container, rather than individual messages, to improve scrolling performance.
Changes to CSS
To support the new container, the following changes can be made to a style's design.css file:
- .historic {
+ #historic_messages,
+ #body_home > .historic {
Changes to Templates
The following changes were made to the baseLayout.mustache template file:
- <div id="body_home"></div>
+ <div id="body_home">
+ <div id="historic_messages"></div>
+ </div>
Style Developers: Migrating to 5.2.0
Changes
-
Added
Textual.dateChanged(dayYear, dayMonth, dayDay)callback which is called at midnight. -
The
Textual.preferencesChanged()callback is now opt-in. To opt-in: add the key “Post Textual.preferencesDidChange() Notifications” as a boolean to a style's styleSettings.plist file. -
Removed the
Textual.sidebarInversionPreferenceChanged()callback in favor ofTextual.preferencesChanged()andapp.sidebarInversionIsEnabled()
Source material
Original Codeux material preserved from the knowledgebase snapshot of 9 September 2026. Formatting and internal links have been adapted for this site.
Need a hand? Contact us about this guide.
