Upgrade your theme
TalkJS continuously releases new features for your chat UI. If you're using a default theme without any changes, then you're automatically up to date. However, if you've customized any theme components, then you may need to update your theme to take advantage of new features.
This page provides an overview of new features for the classic React and classic JavaScript SDKs, and migration guides for how to add these new features to your theme.
If you want to use custom emojis in emoji reactions, and if you made changes to the UserMessage component before the above-mentioned date, then please find the line containing
1<span class="reaction">{{ reaction.emoji }}</span>
and replace it with
1<span class="reaction"><Emoji emoji="{{ reaction.emoji }}" /></span>
The new <Emoji/>
system component will properly display a custom emoji when found.
You can now add action buttons and action links, which let you execute custom code in your chat. You can read more about the feature on the Action Buttons and Links page.
Action buttons come with some pre-defined CSS styles in a couple of component templates. To apply these styles, simply copy-paste the following CSS into the correct templates:
UserMessage
1.by-me button[data-action] {2 color: #0761d1;3 background-color: white;4 border: 1px solid white;5}67.by-me button[data-action]:hover,8.by-me button[data-action]:active {9 color: inherit;10 background-color: transparent;11}1213.by-me button[data-action]:focus-visible {14 outline: white solid 2px;15 outline-offset: 2px;16}1718.by-other button[data-action] {19 color: #111;20 background-color: transparent;21 border: 1px solid #525252;22}2324.by-other button[data-action]:hover {25 color: white;26 background-color: #111;27 border: 1px solid #111;28}2930.by-other button[data-action]:active {31 color: white;32 background-color: #404040;33 border: 1px solid #404040;34}3536.by-other button[data-action]:focus-visible {37 outline: #525252 solid 2px;38 outline-offset: 2px;39}
SystemMessage
1.message button[data-action] {2 border-radius: 0.375rem;3 font-size: inherit;4 margin: 1px 0;5 padding: 0.25rem 0.325rem;6 cursor: pointer;7 transition:8 color 200ms ease-in-out,9 background-color 200ms ease-in-out,10 border 200ms ease-in-out;1112 color: white;13 background-color: #007df9;14 border: 1px solid #007df9;15}1617.message button[data-action]:hover {18 color: white;19 background-color: #0761d1;20 border: 1px solid #0761d1;21}2223.message button[data-action]:active {24 color: white;25 background-color: #3291ff;26 border: 1px solid #3291ff;27}2829.message button[data-action]:focus-visible {30 outline: #007df9 solid 2px;31 outline-offset: 2px;32}
ChatHeader
1.header button[data-action] {2 border-radius: 0.375rem;3 font-size: inherit;4 margin: 1px;5 padding: 0.25rem 0.325rem;6 cursor: pointer;7 transition:8 color 200ms ease-in-out,9 background-color 200ms ease-in-out,10 border 200ms ease-in-out;1112 color: #111;13 background-color: transparent;14 border: 1px solid #525252;15}1617.header button[data-action]:hover {18 color: white;19 background-color: #111;20 border: 1px solid #111;21}2223.header button[data-action]:active {24 color: white;25 background-color: #404040;26 border: 1px solid #404040;27}2829.header button[data-action]:focus-visible {30 outline: #525252 solid 2px;31 outline-offset: 2px;32}
UserMessage
1.by-me button[data-action] {2 color: #0761d1;3 background-color: white;4 border: 1px solid white;5}67.by-me button[data-action]:hover {8 color: inherit;9 background-color: transparent;10}1112.by-me button[data-action]:focus-visible {13 outline: white solid 2px;14 outline-offset: 2px;15}1617.by-other button[data-action] {18 color: white;19 background-color: #525252;20 border: 1px solid #737373;21}2223.by-other button[data-action]:hover {24 color: #111;25 background-color: #f7f7f7;26 border: 1px solid #f7f7f7;27}2829.by-other button[data-action]:active {30 color: #111;31 background-color: #ececec;32 border: 1px solid #ececec;33}3435.by-other button[data-action]:focus-visible {36 outline: #a3a3a3 solid 2px;37 outline-offset: 2px;38}
SystemMessage
1.message button[data-action] {2 border-radius: 0.375rem;3 font-size: inherit;4 margin: 1px 0;5 padding: 0.25rem 0.325rem;6 cursor: pointer;7 transition:8 color 200ms ease-in-out,9 background-color 200ms ease-in-out,10 border 200ms ease-in-out;1112 color: #f7f7f7;13 background-color: #007df9;14 border: 1px solid #007df9;15}1617.message button[data-action]:hover {18 color: white;19 background-color: #3291ff;20 border: 1px solid #3291ff;21}2223.message button[data-action]:active {24 color: white;25 background-color: #0761d1;26 border: 1px solid #0761d1;27}2829.message button[data-action]:focus-visible {30 outline: white solid 2px;31 outline-offset: 2px;32}
ChatHeader
1.header button[data-action] {2 border-radius: 0.375rem;3 font-size: inherit;4 margin: 1px;5 padding: 0.25rem 0.325rem;6 cursor: pointer;7 transition:8 color 200ms ease-in-out,9 background-color 200ms ease-in-out,10 border 200ms ease-in-out;1112 color: white;13 background-color: #525252;14 border: 1px solid #737373;15}1617.header button[data-action]:hover {18 color: #111;19 background-color: #f7f7f7;20 border: 1px solid #f7f7f7;21}2223.header button[data-action]:active {24 color: #111;25 background-color: #ececec;26 border: 1px solid #ececec;27}2829.header button[data-action]:focus-visible {30 outline: #a3a3a3 solid 2px;31 outline-offset: 2px;32}
Users can now mark a conversation as read using a new built-in conversation action. This action renders a small dot inside the conversation's header in the inbox to show that it's been marked as unread. The unread message marker will be removed when the user focuses on the conversation again.
To utilize this feature in your theme you must first add this condition
in your ConversationListItem
template:
use
1<div t:if="{{ isUnread and unreadMessageCount == 0 }}" class="unread-generic-dot"></div>
Afterwards, you must add this unread-generic-dot
CSS class so that a small dot is
shown when the conversation has been marked as unread. The default theme uses the following class:
1.unread-generic-dot {2 padding: 0.6ex;3 transform: scale(0.999);4 border-radius: 999px;5 background-color: #007DF9;6}78.conversation-link.active .unread-generic-dot {9 padding: 0.6ex;10 transform: scale(0.999);11 border-radius: 999px;12 background-color: #fff;13}
The first definition renders the smaller dot inside the conversation's header while the second definition changes its background color when conversation's active.
Support for message attachment previews has just improved. Previously, the thumbnail was a fixed size and very wide or tall images would get cropped. Now, the thumbnail size will adjust to fit the image, and the entire image will always be shown.
If you have previously edited the MessageBody
component in your theme, you will still see some cropping or stretched images.
To add full support for improved attachment thumbnails, first add the location
class to the <span>
containing the location thumbnail, like this:
1<span t:if="{{ body.type == 'location' }}" class="thumbnail location">
Then, update the CSS for the thumbnail
class.
Previously, it used the height
property.
With improved thumbnails, you now specify min-height
and max-height
instead.
This allows the thumbnail to grow and shrink based on the height of the image.
For example:
1.thumbnail {2 display: block;3 min-height: 100px;4 max-height: 500px;5}6.thumbnail.location {7 height: 200px;8}
You can customise the height values to control how big or small the thumbnail becomes.
You can now use unread messages counters. An unread message counter shows the number of unread messages for a particular conversation. It appears next to each conversation's subject inside the inbox.
A counter is incremented or decremented whenever a message arrives or is deleted, respectively. It gets reset (and is removed from view) when a conversation is marked as read - typically whenever a conversation is opened by the user.
To add unread message counters to your theme, update the unread message dot
markup in the ConversationListItem
template to look like this:
1<div t:if="{{ isUnread }}" class="unread-dot">2 <span t:if="{{ unreadMessageCount > 999 }}">3 999+4 </span>5 <span t:else-if="{{ unreadMessageCount > 0 }}">6 {{ unreadMessageCount }}7 </span>8</div>
The t:if="{{ isUnread}}"
attribute ensures that the counter only shows up for
conversations with unread messages.
Conversation actions let users perform actions such as leaving or muting a conversation. New themes include an action menu by default, but if your theme was created before 30 March 2023, you may need to add the menu manually.
To render the action menu button, take the following steps:
- In your theme, find the
ChatHeader
component, and add the followingActionMenu
markup:
1<!-- ChatHeader -->23<div class="actions">4 <ActionMenu class="action-button">5 <Icon type="horizontalDots" />6 </ActionMenu>7</div>
- In the
styles
section of yourChatHeader
component, add the following styles:
1/* ChatHeader */23.actions {4 display: flex;5 gap: 0.5rem;6 align-items: center;7 flex-shrink: 0;8 margin-left: auto;9}1011.action-button {12 /* removing the browser's default button styles: */13 background-color: transparent;14 border: none;15 outline: none;16 color: inherit;17 cursor: pointer;1819 display: flex;20 align-items: center;21 justify-content: center;2223 color: rgba(17, 17, 17, 0.6);24 transition: 0.2s ease-out;2526 /* Increase the tap size of the button */27 box-sizing: content-box;28 padding: 0;29 margin: -0.5rem;30 width: 2.5rem;31 height: 2.5rem;32}3334.action-button + .action-button {35 margin-left: 0;36}
You can customize some of the menu's styling to match the rest of your theme.
Users can now record and play voice messages directly within TalkJS.
Within a theme, this uses the existing mechanism for displaying attachments
so it works out of the box, but if you've created a theme before 2022-10-03,
you may want to apply these changes to the MessageBody
component, in order to
differenciate voice messages from regular audio files:
1- <span t:else-if="{{ body.type == 'file' and body.hasThumbnail }}" class="thumbnail {{ body.file.type }}">2+ <span t:else-if="{{ body.type == 'file' and body.hasThumbnail }}" class="thumbnail {{ body.file.type }} {{body.thumbnailError | then: 'has-error'}}">3 <Thumbnail file="{{ body.file }}" gradients="{{darkenMenuArea | then: 'top-right'}}"/>4 </span>
1- <div class="text timestamp-float-{{ floatTimestamp }}">2+ <div t:if="{{ body.type != 'file' or body.isVoiceMessage == false or body.thumbnailError == true }}" class="text timestamp-float-{{ floatTimestamp }}">3 <span t:if="{{ isLongEmailMessage }}">4 <small><i><Icon type="email" /> {{ strings.MESSAGE_SENT_VIA_EMAIL }}</i></small><br/><br/>5 </span>
1<a class="download-link" href="{{ body.file.url }}" target="_blank" rel="noopener noreferrer">2 <Icon type="download"/>3- <span>{{ body.file.formattedFilename }}</span>4+ <span t:if="{{ body.isVoiceMessage == false }}">{{ body.file.formattedFilename }}</span>5+ <span t:else><Icon type="microphone" /> {{ strings.VOICE_MESSAGE }} ({{ body.recordingDuration | format_duration }})</span>6</a>
Then, in the CSS part of the MessageBody
:
1+ .thumbnail.audio.has-error {2+ padding: 0.5rem;3+ }
Lastly, to show that the last message was a voice message in the conversation list, make the following changes
to the ConversationListItem
component:
1- <span t:if="{{ lastMessage.body.type == 'file' }}">2+ <span t:if="{{ lastMessage.body.type == 'file' and lastMessage.body.isVoiceMessage == false }}">3 <Icon type="image" t:if="{{lastMessage.body.file.type == 'image'}}" />4 <Icon type="movie" t:if="{{lastMessage.body.file.type == 'video'}}" />5 <Icon type="attachment" t:if="{{lastMessage.body.file.type == 'other'}}" />6 <span> {{lastMessage.body.file.filename}}</span>7</span>8+ <span t:if="{{ lastMessage.body.type == 'file' and lastMessage.body.isVoiceMessage == true }}">9+ <span><Icon type="microphone" /> {{ strings.VOICE_MESSAGE }} ({{ lastMessage.body.recordingDuration | format_duration }})</span>10+ </span>
You can now use the new StatusIndicator
element, which shows if a user is online or offline.
If you've created your theme before 2022-09-23, you might have to make some changes to the ChatHeader component in your theme.
To use the Statusindicator element, change these lines in your chatHeader component:
1- <t:set names="{{ conversation.others | map: 'name' | join: ', ' }}" />
1- <div t:if="{{ conversation.formattedSubject }}" class="info">2- <div class="title">{{ conversation.formattedSubject }}</div>3- <div class="subtitle">{{ names }}</div>4- </div>5- <div t:else class="info">6- <div class="title">{{ names }}</div>7- </div>8+ <div t:if="{{ conversation.formattedSubject }}" class="info">9+ <div class="title">{{ conversation.formattedSubject }}</div>10+ <div class="subtitle" >11+ <div class="inline-block user {{ presenceEnabled | then: 'presence-enabled' }}" t:for="{{ user in conversation.others }}" t:key="{{ user.id }}">12+ <span>{{user.name}}</span>13+ <StatusIndicator class="status-indicator" user="{{user}}" />14+ <span class="participant-separator" t:if="{{ presenceEnabled == false and forloop.last == false }}">, </span>15+ </div>16+ </div>17+ </div>18+ <div t:else class="info">19+ <div class="title">20+ <div class="inline-block user {{ presenceEnabled | then: 'presence-enabled' }}" t:for="{{ user in conversation.others }}" t:key="{{ user.id }}">21+ <span>{{user.name}}</span>22+ <StatusIndicator class="status-indicator" user="{{user}}" />23+ <span class="participant-separator" t:if="{{ presenceEnabled == false and forloop.last == false }}">, </span>24+ </div>25+ </div>26+ </div>
1+ .inline-block {2+ display: inline-block;3+ }4+5+ .participant-separator {6+ white-space: pre-wrap;7+ }8+9+ .status-indicator {10+ margin: 0 0.75rem -1px 0.275rem;11+ }
You can now display videos with a wider range of aspect ratios. If you've created a theme before 2022-09-02, you might have to change some styling in the UserMessage component.
To use the styling of the default UserMessage component, change these lines:
1...23- <span t:if="{{ body.type == 'location' }}" class="thumbnail">4+ <span t:if="{{ body.type == 'location' }}" class="thumbnail location">56...78 .thumbnail {9- height: 200px;10 display: block;11 }1213+ .thumbnail.image, .thumbnail.location {14+ height: 200px15+ }1617+ .thumbnail.video {18+ max-height: 400px19+ }
TalkJS now support emoji reactions. If you've created a theme before 2022-08-18, you have to add the code for displaying emoji reactions in the UserMessage component. There are two new system components for emoji reactions:
<EmojiReactionButton>
renders a button that the user can click to react with a given emoji, or click again to remove their reaction.<AddEmojiReaction>
a button that also lets the user add an emoji reaction, but it'll pop up an emoji picker for the user to choose an emoji.
So, before the closing </template>
tag, add the following snippet to the UserMessage component:
1<div t:if="{{ reactions and reactions.length > 0 }}" class="emoji-reactions {{ sender.isMe | then: 'by-me' | else: 'by-other' }}">2 <EmojiReactionButton t:for="{{ reaction in reactions }}" t:key="{{ reaction.emoji }}" class="emoji-reaction {{ reaction.iReacted | then: 'i-reacted' }}" emoji="{{ reaction.emoji }}" numReactions="{{ reaction.numReactions }}" iReacted="{{ reaction.iReacted }}">3 <span class="reaction">{{ reaction.emoji }}</span>4 <span class="num-reactions" t:if="{{ reaction.numReactions > 1 }}">{{ reaction.numReactions }}</span>5 </EmojiReactionButton>67 <AddEmojiReaction class="add-emoji-reaction" t:if="{{ canReact }}">8 <Icon type="addEmoji" class="icon" />9 </AddEmojiReaction>10</div>
Then, to style the emoji reactions, if you used the above snippet, you will have:
.emoji-reactions
which points to the emoji reactions<div>
. This<div>
can hav either theby-me
or theby-other
class, depending whether the message is by the current user or not..emoji-reaction
is the button containing the emoji reaction. This button can also have thei-reacted
class if the current user reacted with that emoji. This button also has 2 children:.reaction
which is the emoji.num-reactions
which is the number of people who reacted with that emoji
.add-emoji-reaction
is the button for adding an emoji reaction
To use the styling of the default theme, add the following in the <style>
section of the UserMessage component:
1.emoji-reactions {2 margin-top: -0.25rem;3 margin-bottom: 1.75rem;4 display: flex;5 flex-wrap: wrap;6 gap: 0.25rem;7}8.emoji-reactions.by-me {9 justify-content: flex-end;10 margin-right: 3.25rem;11}12.emoji-reactions.by-other {13 margin-left: 3.25rem;14}15.emoji-reaction {16 border: 1px solid transparent;17 margin: 0;18 padding: 0.2rem 0.55rem;19 border-radius: 8rem;20 background-color: #e8ecee;21}22.emoji-reaction.i-reacted {23 background: #1E60E1;24 border: 1px solid transparent;25 color: white;26}27.emoji-reaction.i-reacted:hover {28 background: #1E60E1;29 border: 1px solid transparent;30}31.emoji-reaction span {32 display: inline-block;33 vertical-align: middle;34}35.emoji-reaction .reaction {36 font-size: 1.25rem;37}38.emoji-reaction .num-reactions {39 padding-left: 0.25rem;40 font-size: 0.85rem;41}42.add-emoji-reaction {43 border: 1px solid transparent;44 margin: 0rem;45 padding: 0.15rem 0.75rem;46 border-radius: 8rem;47 background-color: #e8ecee;48 color: #111;49}50.emoji-reaction:hover,51.add-emoji-reaction:hover {52 border: 1px solid #b5c0c6;53}54.add-emoji-reaction .icon {55 width: 1.5rem;56 height: 1.5rem;57}
After saving the aformentioned changes, emoji reactions will be rendered in the TalkJS UI.
You can now play audio attachments directly within TalkJS. Within themes, this uses the existing mechanism for displaying attachments so it works out of the box, but if you've created a theme before 2022-08-17, you may want to apply a style tweak to give the player the correct height.
The thumbnail is rendered inside the MessageBody component, so that's where
you'll make the change.
Since you want to apply the styling only for audio files, you can add the file
type as a class on the <span>
that wraps the thumbnail.
You can then add some CSS to set the height to auto
when there's a thumbnail
for an audio file.
MessageBody component:
1...23- <span t:else-if="{{ body.type == 'file' and body.hasThumbnail }}" class="thumbnail">4+ <span t:else-if="{{ body.type == 'file' and body.hasThumbnail }}" class="thumbnail {{ body.file.type }}">5 <Thumbnail file="{{ body.file }}" gradients="{{darkenMenuArea | then: 'top-right'}}"/>6</span>78...910.thumbnail {11 height: 200px;12 display: block;13}1415+ .thumbnail.audio {16+ height: auto;17+ }
After saving the aformentioned changes, the audio player will have the correct size.
If you want to allow users to reply to messages (described in this changelog entry) and you edited the theme before 08/07/2022 you need to manually pass hasReferencedMessage
from UserMessage component to the MessageBody component, and then inside the message body, render the referenced message.
UserMessage component:
1<MessageBody2 body="{{ body }}"3 timestamp="{{ timestamp }}"4 editedAt="{{ editedAt }}"5 floatTimestamp="auto"6 showStatus="{{ sender.isMe }}"7 isLongEmailMessage="{{isLongEmailMessage}}"8 darkenMenuArea="{{ darkenMenuArea }}"9 isSystemMessage="{{ false }}"10+ hasReferencedMessage="{{ hasReferencedMessage }}11/>
MessageBody component:
1...2<template>34+ <div t:if="{{ hasReferencedMessage }}" class="referencedMessage">5+ <ReferencedMessage />6+ </div>78 <span t:if="{{ body.type == 'location' }}" class="thumbnail">9 <Thumbnail location="{{ body.location }}" gradients="{{darkenMenuArea | then: 'top-right'}}"/>10 </span>11 <span t:else-if="{{ body.type == 'file' and body.hasThumbnail }}" class="thumbnail">12 <Thumbnail file="{{ body.file }}" gradients="{{darkenMenuArea | then: 'top-right'}}"/>13 </span>14...1516+ .referencedMessage {17+ padding: 10px 0px 5px 0px;18+ }1920+ .referencedMessage ~ .text {21+ padding-top: 0;22+ }
After saving the aformentioned changes, replies will be rendered in the TalkJS UI.