Message
A chat message layout that pairs an avatar with bubbles, headers, and footers. Built on top of Avatar and Bubble.
Usage
Conversation
div(class: "flex flex-col gap-6") do
Message(align: :end) do
MessageAvatar do
Avatar(size: :sm) do
AvatarImage(src: "https://github.com/joeldrapper.png", alt: "@me")
AvatarFallback { "ME" }
end
end
MessageContent do
Bubble do
BubbleContent { "Deploying to prod real quick." }
end
end
end
Message do
MessageAvatar do
Avatar(size: :sm) do
AvatarImage(src: "https://github.com/shadcn.png", alt: "@rabbit")
AvatarFallback { "R" }
end
end
MessageContent do
Bubble(variant: :muted) do
BubbleContent { "It's 4:55 PM. On a Friday." }
end
end
end
Message(align: :end) do
MessageAvatar do
Avatar(size: :sm) do
AvatarImage(src: "https://github.com/joeldrapper.png", alt: "@me")
AvatarFallback { "ME" }
end
end
MessageContent do
Bubble do
BubbleContent { "It's a one-line change." }
end
MessageFooter { "Delivered" }
end
end
Message do
MessageAvatar do
Avatar(size: :sm) do
AvatarImage(src: "https://github.com/shadcn.png", alt: "@rabbit")
AvatarFallback { "R" }
end
end
MessageContent do
BubbleGroup do
Bubble(variant: :muted) do
BubbleContent { "It's always a one-line change 😭." }
end
Bubble(variant: :muted) do
BubbleContent { "Alright, let me take a look." }
BubbleReactions(role: "img", aria_label: "Reaction: thumbs up") do
span { "👍" }
end
end
end
end
end
end
With header
Alignment
Sender and receiver
div(class: "flex flex-col gap-6") do
Message do
MessageAvatar do
Avatar(size: :sm) do
AvatarImage(src: "https://github.com/shadcn.png", alt: "@rabbit")
AvatarFallback { "R" }
end
end
MessageContent do
Bubble(variant: :muted) { BubbleContent { "Aligned to the start." } }
end
end
Message(align: :end) do
MessageAvatar do
Avatar(size: :sm) do
AvatarImage(src: "https://github.com/joeldrapper.png", alt: "@me")
AvatarFallback { "ME" }
end
end
MessageContent do
Bubble { BubbleContent { "Aligned to the end." } }
end
end
end
Group
Message group
MessageGroup do
Message do
MessageAvatar do
Avatar(size: :sm) do
AvatarImage(src: "https://github.com/shadcn.png", alt: "@rabbit")
AvatarFallback { "R" }
end
end
MessageContent do
Bubble(variant: :muted) { BubbleContent { "First message." } }
end
end
Message do
MessageAvatar do
Avatar(size: :sm) do
AvatarImage(src: "https://github.com/shadcn.png", alt: "@rabbit")
AvatarFallback { "R" }
end
end
MessageContent do
Bubble(variant: :muted) { BubbleContent { "Second, tighter spacing." } }
end
end
end
Installation
Using RubyUI CLI
Run the install command
rails g ruby_ui:component Message
Manual installation
1
Add RubyUI::Message to app/components/ruby_ui/message/message.rb
# frozen_string_literal: true
module RubyUI
class Message < Base
def initialize(align: :start, **attrs)
@align = align
super(**attrs)
end
def view_template(&)
div(**attrs, &)
end
private
def default_attrs
{
data: {slot: "message", align: @align},
class: "group/message relative flex w-full min-w-0 gap-2 text-sm data-[align=end]:flex-row-reverse"
}
end
end
end
2
Add RubyUI::MessageAvatar to app/components/ruby_ui/message/message_avatar.rb
# frozen_string_literal: true
module RubyUI
class MessageAvatar < Base
def view_template(&)
div(**attrs, &)
end
private
def default_attrs
{
data: {slot: "message-avatar"},
class: "flex w-fit min-w-8 shrink-0 items-center justify-center self-end overflow-hidden rounded-full bg-muted group-has-data-[slot=message-footer]/message:-translate-y-8"
}
end
end
end
3
Add RubyUI::MessageContent to app/components/ruby_ui/message/message_content.rb
# frozen_string_literal: true
module RubyUI
class MessageContent < Base
def view_template(&)
div(**attrs, &)
end
private
def default_attrs
{
data: {slot: "message-content"},
class: "flex w-full min-w-0 flex-col gap-2.5 wrap-break-word group-data-[align=end]/message:[&>[data-slot]]:self-end"
}
end
end
end
4
Add RubyUI::MessageDocs to app/components/ruby_ui/message/message_docs.rb
# frozen_string_literal: true
class Views::Docs::Message < Views::Base
def view_template
component = "Message"
div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
render Docs::Header.new(title: "Message", description: "A chat message layout that pairs an avatar with bubbles, headers, and footers. Built on top of Avatar and Bubble.")
Heading(level: 2) { "Usage" }
render Docs::VisualCodeExample.new(title: "Conversation", context: self) do
<<~RUBY
div(class: "flex flex-col gap-6") do
Message(align: :end) do
MessageAvatar do
Avatar(size: :sm) do
AvatarImage(src: "https://github.com/joeldrapper.png", alt: "@me")
AvatarFallback { "ME" }
end
end
MessageContent do
Bubble do
BubbleContent { "Deploying to prod real quick." }
end
end
end
Message do
MessageAvatar do
Avatar(size: :sm) do
AvatarImage(src: "https://github.com/shadcn.png", alt: "@rabbit")
AvatarFallback { "R" }
end
end
MessageContent do
Bubble(variant: :muted) do
BubbleContent { "It's 4:55 PM. On a Friday." }
end
end
end
Message(align: :end) do
MessageAvatar do
Avatar(size: :sm) do
AvatarImage(src: "https://github.com/joeldrapper.png", alt: "@me")
AvatarFallback { "ME" }
end
end
MessageContent do
Bubble do
BubbleContent { "It's a one-line change." }
end
MessageFooter { "Delivered" }
end
end
Message do
MessageAvatar do
Avatar(size: :sm) do
AvatarImage(src: "https://github.com/shadcn.png", alt: "@rabbit")
AvatarFallback { "R" }
end
end
MessageContent do
BubbleGroup do
Bubble(variant: :muted) do
BubbleContent { "It's always a one-line change 😭." }
end
Bubble(variant: :muted) do
BubbleContent { "Alright, let me take a look." }
BubbleReactions(role: "img", aria_label: "Reaction: thumbs up") do
span { "👍" }
end
end
end
end
end
end
RUBY
end
Heading(level: 2) { "With header" }
render Docs::VisualCodeExample.new(title: "Header and footer", context: self) do
<<~RUBY
Message do
MessageAvatar do
Avatar(size: :sm) do
AvatarImage(src: "https://github.com/shadcn.png", alt: "@oliver")
AvatarFallback { "OL" }
end
end
MessageContent do
MessageHeader { "Oliver" }
Bubble(variant: :muted) do
BubbleContent { "Pushed the fix, can you review?" }
end
MessageFooter { "9:41 AM" }
end
end
RUBY
end
Heading(level: 2) { "Alignment" }
render Docs::VisualCodeExample.new(title: "Sender and receiver", context: self) do
<<~RUBY
div(class: "flex flex-col gap-6") do
Message do
MessageAvatar do
Avatar(size: :sm) do
AvatarImage(src: "https://github.com/shadcn.png", alt: "@rabbit")
AvatarFallback { "R" }
end
end
MessageContent do
Bubble(variant: :muted) { BubbleContent { "Aligned to the start." } }
end
end
Message(align: :end) do
MessageAvatar do
Avatar(size: :sm) do
AvatarImage(src: "https://github.com/joeldrapper.png", alt: "@me")
AvatarFallback { "ME" }
end
end
MessageContent do
Bubble { BubbleContent { "Aligned to the end." } }
end
end
end
RUBY
end
Heading(level: 2) { "Group" }
render Docs::VisualCodeExample.new(title: "Message group", context: self) do
<<~RUBY
MessageGroup do
Message do
MessageAvatar do
Avatar(size: :sm) do
AvatarImage(src: "https://github.com/shadcn.png", alt: "@rabbit")
AvatarFallback { "R" }
end
end
MessageContent do
Bubble(variant: :muted) { BubbleContent { "First message." } }
end
end
Message do
MessageAvatar do
Avatar(size: :sm) do
AvatarImage(src: "https://github.com/shadcn.png", alt: "@rabbit")
AvatarFallback { "R" }
end
end
MessageContent do
Bubble(variant: :muted) { BubbleContent { "Second, tighter spacing." } }
end
end
end
RUBY
end
render Components::ComponentSetup::Tabs.new(component_name: component)
# components
render Docs::ComponentsTable.new(component_files(component))
end
end
end
5
Add RubyUI::MessageFooter to app/components/ruby_ui/message/message_footer.rb
# frozen_string_literal: true
module RubyUI
class MessageFooter < Base
def view_template(&)
div(**attrs, &)
end
private
def default_attrs
{
data: {slot: "message-footer"},
class: "flex max-w-full min-w-0 items-center px-3 text-xs font-medium text-muted-foreground group-data-[align=end]/message:justify-end group-has-data-[variant=ghost]/message:px-0"
}
end
end
end
6
Add RubyUI::MessageGroup to app/components/ruby_ui/message/message_group.rb
# frozen_string_literal: true
module RubyUI
class MessageGroup < Base
def view_template(&)
div(**attrs, &)
end
private
def default_attrs
{
data: {slot: "message-group"},
class: "flex min-w-0 flex-col gap-2"
}
end
end
end
7
Add RubyUI::MessageHeader to app/components/ruby_ui/message/message_header.rb
# frozen_string_literal: true
module RubyUI
class MessageHeader < Base
def view_template(&)
div(**attrs, &)
end
private
def default_attrs
{
data: {slot: "message-header"},
class: "flex max-w-full min-w-0 items-center px-3 text-xs font-medium text-muted-foreground group-has-data-[variant=ghost]/message:px-0"
}
end
end
end
8
Install required components
Component Message relies on the following RubyUI components. Refer to their individual installation guides for setup instructions:
Components
| Component | Built using | Source |
|---|---|---|
Message | Phlex | |
MessageAvatar | Phlex | |
MessageContent | Phlex | |
MessageDocs | Phlex | |
MessageFooter | Phlex | |
MessageGroup | Phlex | |
MessageHeader | Phlex |

