For the complete documentation index, see llms.txt. This page is also available as Markdown.

Case thread with a pinned workaround

A support conversation on the Case record: received and sent bubbles, a pinned workaround at the top, a mention to escalate, a reply box.

Overview

A support conversation on the Case record: received and sent bubbles, a pinned workaround at the top, a mention to escalate, a reply box. The agent never leaves the case. The whole thing is one Chat Dynamic Component placed under the highlights panel of the Case record page, first with a Manual data source that holds the eight messages of the figure, then with a Query data source on a message object for production. This tutorial rebuilds the case Sync fails after update 4.1 of Halden Robotics in your own org.

What you build

Avonni Chat on a Salesforce Case record page: a support thread with received and sent bubbles, a pinned workaround banner, a day break, a mention and a reply box
  • Open the case and the conversation sits under the highlights panel. Rafael Duarte writes from the left, Lena Okafor answers from the right, initials in the avatars.

  • A day break separates September 3 from September 4.

  • Lena's workaround is pinned: a banner above the thread repeats it, and the message itself is marked Pinned.

  • A mention pulls Jonas Lindqvist in, and he answers in the same thread.

  • Escalate and Close case sit in the header, the reply box at the bottom with a formatting toolbar and a Send button.

Before you start

Adapt this to your own org. The figure is built with the eight messages typed into the component, so reproducing it asks for nothing but a case. Case Message, the object behind the production path in step 8, is one this tutorial creates. Point the query at whatever holds your correspondence instead, and map the two fields the thread lives on: one that says which side a bubble sits on, holding exactly inbound or outbound, and a checkbox that keeps a pin. A field that stores the direction another way needs a formula returning those two words.

  • The Avonni Experience Components package, which carries Dynamic Components, is installed. Whoever builds the component needs the Avonni Experiences Admin permission set; the people who use the page need a license and Avonni Dynamic Components User. See Installation & Licenses Management.

  • A Case record page in a Lightning app. The examples use the Support app and a case with Subject Sync fails after update 4.1, Status Working, Priority High, Contact Rafael Duarte and Account Halden Robotics. The figure shows a page with the highlights panel and the chat alone below it, at a tighter spacing than the default: on a standard record page the thread is taller, and the last message may sit below the fold.

  • For the Manual build (steps 1 to 7), no object beyond the Case. For the Query path (steps 8 and 9), a message object linked to the case:

Object
Field
Type
Role

Case (standard)

Subject, Status, Priority, ContactId, AccountId

Standard

The record the chat lives on

Case Message (Case_Message__c)

Case__c

Lookup (Case)

Links the message to its case; the query filters on it

Body__c

Rich Text Area

The message content

Direction__c

Picklist: inbound, outbound

Which side the bubble sits on. Lowercase, exactly these two values

Pinned__c

Checkbox

Keeps a message pinned from one visit to the next

CreatedById, CreatedDate

Standard

The author and the time, used by default

Sample data. Three participants and eight messages over two days. The times are the ones the figure shows; the chat displays every time in the viewer's time zone, so enter them in yours.

Participant
Name
Initials

Rafael Duarte, the customer at Halden Robotics

rafael

RD

Lena Okafor, the support agent

lena

LO

Jonas Lindqvist, the colleague Lena mentions

jonas

JL

#
From
Type
Date and time
Content

1

Rafael Duarte

Inbound

Sep 3, 2026, 9:12 AM

Since update 4.1 the nightly sync stops at 40 % with "token expired". Logs attached to the case.

2

Lena Okafor

Outbound

Sep 3, 2026, 9:40 AM

Thanks Rafael, looking at the logs now. Which connector version shows in Setup?

3

Rafael Duarte

Inbound

Sep 3, 2026, 9:47 AM

Connector 2.8.3, region EU.

4

Lena Okafor

Outbound

Sep 3, 2026, 11:05 AM

Workaround until patch 4.1.2: set the sync window to 30 minutes and re-authorize the connector once. The full run completes in two passes.

5

Rafael Duarte

Inbound

Sep 3, 2026, 11:30 AM

Done. First pass finished, second one running.

6

Rafael Duarte

Inbound

Sep 4, 2026, 8:15 AM

Both passes completed overnight. When is 4.1.2 due?

7

Lena Okafor

Outbound

Sep 4, 2026, 8:52 AM

@Jonas Lindqvist can you confirm the release window for 4.1.2?

8

Jonas Lindqvist

Outbound

Sep 4, 2026, 9:10 AM

Patch is in staging, production release Tuesday. I will update this case.

Permissions. Read on Case for everyone who opens the page, plus the Avonni Dynamic Components User permission set. On the Query path, Read on Case Message to see the thread and Create on it to post from the reply box: the query and the Create Record interaction both run with the user's own permissions.

Build it

1

Create the Dynamic Component on Case

  1. Open the Avonni Components app and click New Component. Name the component Case thread and set the Target Page Object to Case.

  2. From the Component Library, drag Chat onto the Canvas.

  3. Select it. The Edit Chat panel opens on the right, with its Properties, Interactions and Style tabs.

Why: the Target Page Object gives the component the Id of the case it sits on. The Manual build does not need it yet; the Query path filters on it.

The Dynamic Component builder with the Chat selected on the canvas, the eight messages rendered, and its Edit Chat panel on the right
The Chat on the canvas, once the participants and messages of steps 2 and 3 are entered.
2

Enter the participants

  1. In Data Source, select Manual.

  2. Under Resources, add three entries. For each one set Label and Avatar Initials from the participants table, then expand the advanced options of the entry and set Name to rafael, lena and jonas.

Why: Name is the key each message points to, and the value Current Resource ID is compared against. Avatar Initials draw the RD, LO and JL circles; Avatar Source takes a photo instead when you have one.

The Data Source section on Manual with the Resources list: Rafael Duarte, Lena Okafor, Jonas Lindqvist
The three participants.
3

Enter the eight messages

Under Messages, add the eight rows of the sample table, oldest first. For each one: Participant Name (pick the participant), Type Inbound or Outbound, Date, Content.

  • Message 4 starts in bold: format the first words in the Content editor.

  • Message 7 carries the mention: type @Jonas Lindqvist and turn those words into a link to Jonas's user record. That is what the reply box writes when the end user picks a mention, and it renders in blue.

Why: Type decides the side of the bubble. Rafael is Inbound, so he sits on the left whoever is looking; Lena and Jonas are Outbound, on the right. With a type on every message, Current Resource ID no longer decides sides, only who authors new messages.

The Messages list with the eight messages, oldest first
The eight messages.
4

Set the general settings

  1. Current Resource ID lena.

  2. Message Date Format Preset, then Preset Time Simple (1:30 PM).

  3. Turn on Show Date Dividers.

  4. Turn on Can Pin. Leave Max Pinned Messages at 10.

Why: the default date format is Relative (2 hours ago), which ages badly on a thread you come back to; Time Simple prints 11:05 AM under each block of messages. Show Date Dividers inserts Sep 3, 2026 and Sep 4, 2026. Can Pin adds the message menu and the pinned banner.

The Content section: Current Resource ID lena, Message Date Format Preset, Preset Time Simple (1:30 PM), Show Date Dividers on, Can Pin on, Max Pinned Messages 10
The general settings, in the Content section.
5

Build the header

  1. Title Conversation, Caption Rafael Duarte · Halden Robotics.

  2. Under Avatar, Initials RD; in its advanced options, Size Medium and Variant Circle.

  3. Under Actions, add two actions:

    • Label Escalate, Name escalate, Icon Name utility:priority

    • Label Close case, Name close, Icon Name utility:check

  4. Visible Actions Buttons 2.

Why: with as many visible buttons as actions, both gestures stay one click away. Fewer, and the rest collapse into an overflow menu.

The Header section: Title Conversation, Caption Rafael Duarte · Halden Robotics, Avatar Initials RD, the Escalate and Close case actions, Visible Actions Buttons 2
The header, its avatar and the two actions.
6

Configure the reply box

In the Publisher group:

  1. Mode Rich.

  2. Turn on Allow Mentions.

  3. Placeholder Reply to Rafael, Publish Button Label Send.

  4. Toolbar Position Bottom.

  5. Categories: keep Text only.

Why: mentions need the rich editor, so Mode stays Rich. Text gives bold, italic, underline and strikethrough and nothing else, which is what a support reply needs. The bottom toolbar keeps the typing area at the top of the box.

The Publisher section: Mode Rich, Allow Mentions on, Placeholder Reply to Rafael, Publish Button Label Send, Toolbar Position Bottom, Categories Text
The reply box settings.
7

Preview, save, activate, add to the Case record page

  1. Click Preview: eight bubbles, two day dividers, the header with its two buttons, the reply box.

  2. Click Save, then Activate, and follow Publishing your Dynamic Components: in Lightning App Builder, edit the Case record page, drag AX - Dynamic Component under the highlights panel, select Case thread in its properties, then Save and Activate the page.

  3. Open the case. Pin the workaround from the thread, as described in Try it.

Why: pinning is a gesture of the end user, not a setting. With a Manual data source the pin lasts until the page reloads; the Query path below stores it in a field.

8

Production: switch to a Query data source

The Manual list is frozen. For a live case, the messages are records.

  1. Create the Case Message object with the fields listed above, and a few records on a test case. Direction__c holds inbound or outbound, in lowercase.

  2. In Data Source, select Query. Object Case_Message__c. Add a filter: Field Case__c, Operator equals, Value {!$Component.RecordId}. Order By CreatedDate ASC.

  3. In Data Mappings, set Content to Body__c. Date stays on CreatedDate. In the advanced options, set Type to Direction__c and Pinned to Pinned__c. Leave Participant ID empty: the author of each message defaults to the user who created the record, and Participant lets you map that user's label and avatar if the defaults are not what you want.

  4. Clear Current Resource ID: it defaults to the running user, who then authors what is sent from the reply box. The sides still come from Direction__c.

Why: a customer writing through your Experience site is a user too, so a thread built this way reads like the figure. Pinned__c is what makes a pin outlive the page: records where it is true show as pinned when the thread loads.

The query editor popover for the Case Message object: Case equals {!$Component.RecordId}, Order By Created Date ascending
The query on Case Message, filtered on the record the page is on.
The Data Mappings section with Advanced Options expanded: Content Body, Date Created Date, Key Field Id, Type Direction, Pinned mapped to the Pinned field, Reply To and Participant ID empty
The mappings on the Query path. Type and Pinned are under Advanced Options.
9

Wire the reply box to create the message

  1. Open the Interactions tab. On Publish a New Message, add a Create Record action.

  2. In Record Variable, select Enter Record Data Manually, then Object Case_Message__c.

  3. Map the fields: Case__c to {!$Component.RecordId}, Body__c to the content of the message the end user sent (the chat's Last Publication Value output), Direction__c to outbound.

  4. On success, add Refresh Query so the new bubble appears, and a Show Toast if you want a confirmation.

Why: without an action on Publish a New Message, Send clears the box and stores nothing. The chat exposes the sent text and the mentioned participants as outputs; the interaction turns them into a record, and the query redraws the thread.

The Interactions tab with the Create Record interaction open on Publish a New Message: Object Case Message, the Case, Body and Direction mappings, and Refresh Query then Show Toast Notification on success
The Create Record interaction on Publish a New Message, with Refresh Query and the toast on success.

The settings that matter

Setting
Value
Why

Can Pin (canPin)

on

The workaround stays visible in a banner above the thread, and the end user pins or unpins from the message menu.

Type on each message (items[].type, or Direction__c mapped to Type on the Query path)

Inbound for Rafael, Outbound for Lena and Jonas

Who sits left and who sits right, whoever is looking at the page.

Current Resource ID (currentResourceId)

lena in the Manual build, empty on the Query path

The author of new messages. With a type on every message it does not move any bubble.

Show Date Dividers (showTimeBreaks) and Message Date Format (itemDateFormat)

on, Preset Time Simple

The day change is a divider, the time sits under each block of messages.

Publisher (publisher)

Mode Rich, Allow Mentions on, Placeholder Reply to Rafael, Publish Button Label Send, Categories Text

Mentions need the rich editor; the button and the placeholder speak the agent's language.

Interactions

Trigger
Action
What to set

Publish a New Message

Create Record, Enter Record Data Manually

Object Case_Message__c; Case__c = {!$Component.RecordId}, Body__c = the published message (Last Publication Value), Direction__c = outbound. Then Refresh Query. Query path only.

Publish a New Message

Execute Flow, optional

An escalation flow that takes Last Publication Mentions, the Ids of the participants mentioned with @, as input. Works with either data source.

Header Action Click, Target Name escalate

The escalation screen flow, with {!$Component.RecordId} as its case input.

Header Action Click, Target Name close

The current page record, Status = Closed. Add a Show Toast on success.

Pin a Message and Unpin a Message

Query path only: set Pinned__c to true or false on the message the trigger exposes as Item, so the pin is shared by everyone who opens the case. Without it, the pin is kept for the current page view only.

Try it

  1. Open the case. Eight bubbles: RD on the left in gray, LO and JL on the right in blue, Sep 3, 2026 above the thread and Sep 4, 2026 between the 11:30 AM and 8:15 AM messages.

  2. Hover Lena's 11:05 AM message, click the menu that appears beside the bubble and select Pin Message. The banner Most recent pinned messages (1/10) appears above the thread with her name, the time and the text, and the message reads Pinned under its time. Open the menu again: it now offers Unpin Message.

  3. Click in the reply box: the placeholder Reply to Rafael and the bold, italic, underline and strikethrough toolbar appear under it, and Send stays gray until you type. Type @Jon: the dropdown offers Jonas Lindqvist.

Take it further

The same Chat exists for LWC Components: Chat, as the avonni-dd-chat tag in your own component, with the same messages and participants or a query and a mapping. Flow Screen Components and Experience Sites have no Chat component today.

Three variations worth trying:

  • Turn on Read Only for closed cases: the thread stays, the reply box goes.

  • Restrict who can be mentioned with Mentionable Participants IDs, and block words with Blocked Words.

  • Add Real-Time Data on the Query path, so a message the customer posts appears without a reload.

Troubleshooting

Problem
Cause
Fix

All messages sit on the same side

With no Type on the messages, the side comes from Current Resource ID, compared to the participant Name exactly, case included: Lena and lena are two people. On the Query path, Direction__c holds a value other than inbound or outbound.

Set Type on each message, or map Type to a field that holds exactly those two values; or make Current Resource ID match the participant Name.

No menu appears beside the messages

Can Pin is off. The message menu exists only when it is on, and it shows on hover.

Turn on Can Pin in the general settings, then hover a bubble.

The pinned banner is gone after a reload

With a Manual data source, a pin lives in the page, not in a record.

Use the Query path: map Pinned to a checkbox field and wire Pin a Message and Unpin a Message to an Update Record on that field.

Some messages show no name or time, or no avatar

Consecutive messages from the same author form a block: the avatar is drawn on the first one, the name and time under the last one. Message 5 has neither, because message 6 follows from Rafael.

Nothing to configure. This is how the thread groups a run of messages.

Typing @ opens no dropdown, or the dropdown does not find a name

Mode is Plain or Allow Mentions is off. Or the text typed after @ contains a character other than letters, spaces and hyphens (O'Brien), which the mention search does not accept.

Set Mode to Rich and turn on Allow Mentions. Search on the part of the name made of letters, @Brien.

The thread reads No messages yet on the Query path, even though records exist

The query returns nothing: the filter does not match, or in Preview no record context is set.

Check that the filter reads Case__c equals {!$Component.RecordId}, then in Preview open the Debug Panel and set a Preview Context record that has messages.

Was this helpful?