Chat Kit is present on the main branch, which currently targets LanternUI 0.8.0. Hex 0.8 is not published yet. Install the reproducible git revision below until that release is available:
{:lantern_ui, git: "https://github.com/go9/lantern-ui.git", ref: "0ad0627054ee6765c81eceace58ad316959565bb"}Chat Kit is a composed model for conversations. Avatar, Message, and
MessageScroller are designed to work together: avatars provide identity,
messages provide visual alignment and tone, and the scroller provides the
follow-aware transcript viewport. The host LiveView owns the messages, state,
events, and content.
Composed example
In a LiveView that uses LanternUI, render the conversation from host-owned
assigns. This example expects @messages to contain maps with :id, :role,
and :content keys, and @streaming to be a boolean:
<.message_scroller id="conversation" label="Conversation" follow={true} busy={@streaming}>
<.message_scroller_item
:for={message <- @messages}
id={"message-#{message.id}"}
message_id={to_string(message.id)}
scroll_anchor={message.role == :assistant}
>
<.message
align={if message.role == :user, do: "end", else: "start"}
tone={if message.role == :user, do: "primary", else: "surface"}
>
<:avatar>
<.avatar initials={if message.role == :user, do: "You", else: "AI"} />
</:avatar>
<:header>{if message.role == :user, do: "You", else: "Assistant"}</:header>
{message.content}
<:footer :if={message.role == :assistant}>Assistant response</:footer>
</.message>
</.message_scroller_item>
<.message_scroller_item :if={@streaming} id="streaming-message" message_id="streaming">
<.message align="start" tone="surface">
<:avatar><.avatar initials="AI" /></:avatar>
<:header>Assistant</:header>
<span aria-label="Assistant is responding">...</span>
<:footer>Streaming</:footer>
</.message>
</.message_scroller_item>
</.message_scroller>The host can replace the text content with rendered markdown or other content. It should also assign stable item ids and update the message content as the conversation changes.
Following the latest message
follow={true} starts the viewport at the bottom and follows new content only
while the user remains at the bottom. Scrolling away pauses follow. The
Jump to latest control then becomes keyboard reachable; clicking it resumes
follow and returns to the latest content.
Mark an item with scroll_anchor={true} when a newly appended turn should be
positioned with context still visible above it. The peek value controls that
position. For example:
<.message_scroller_item id="assistant-turn" scroll_anchor={true}>
<.message>Here is the next turn.</.message>
</.message_scroller_item>Streaming
The scroller hook observes streamed token patches as well as appended message
nodes. The host should update message content through normal LiveView assigns or
streams, not issue manual JavaScript scroll commands. Set busy={true} while a
response is being produced; busy maps to aria-busy="true" on the transcript
log.
Accessibility
The scroller renders a labelled region containing a log with aria-live="polite"
and aria-relevant="additions". The host remains responsible for semantic
message author labelling, including making the relationship between an author
and its message clear to assistive technology. The example's header slot is
visual metadata and is not a substitute for host-owned author semantics.
The jump-to-latest button is keyboard reachable when the user is away from the bottom. Reduced-motion preferences are respected by the hook when returning to the latest content.
Theming and imports
Import both lantern_ui_theme.css and lantern_ui.css for the default theme:
@import "../../deps/lantern_ui/priv/static/lantern_ui_theme.css";
@import "../../deps/lantern_ui/priv/static/lantern_ui.css";The Chat Kit-specific tokens are:
--lantern-chat-avatar-xs--lantern-chat-message-max-width--lantern-chat-scroller-padding-bottom--lantern-chat-item-intrinsic-height--lantern-chat-button-offset--lantern-chat-button-visibility-duration
Chat Kit also consumes these shared tokens:
--lantern-surface-raised--lantern-fg--lantern-fg-muted--lantern-fg-subtle--lantern-border--lantern-primary--lantern-primary-fg--lantern-radius--lantern-radius-sm--lantern-space-xs--lantern-space-sm--lantern-space-md--lantern-shadow--lantern-duration--lantern-ease
Importing lantern_ui_theme.css supplies all of these tokens. A host theme
that imports only lantern_ui.css must define every token listed above.