Skip to content

Mobile-Responsive Layout

The messaging module uses a responsive layout that switches between a multi-column desktop view and a single-panel mobile view at the 768px breakpoint. On mobile, navigation between the contact list and conversation happens via route changes instead of side-by-side panels.

MessagingView renders a 4-column grid: contact list (1 column) + conversation feed and sidebar (3 columns). Clicking a contact navigates to /messaging/:contact_id, which shows the contact list alongside the conversation and sidebar panel.

The grid collapses to a single column. Each route shows one panel at a time:

RouteWhat’s Visible
/messagingFull-width contact list
/messaging/:contact_idFull-width conversation with back button

The conversation sidebar (contact info, notes, activity, tasks) is hidden on mobile. Users access contact details through the external link in the conversation header.

The layout uses Tailwind’s md: prefix (768px) to toggle visibility:

// messaging_view.rs — grid switches from 1 to 4 columns
div { class: "grid grid-cols-1 md:grid-cols-4 h-full",
// Contact list: always visible
div { class: "col-span-1 ...",
// Empty state: hidden on mobile
div { class: "hidden md:flex md:col-span-3 ...",
// messaging_contact_view.rs — contact list hidden, back button shown on mobile
div { class: "hidden md:block md:col-span-1 ...", // contact list sidebar
div { class: "md:hidden", // back button, mobile only
ArrowLeft {}
"Back"
PatternMobileDesktop
grid-cols-1 md:grid-cols-41 column4 columns
hidden md:flexHiddenFlex
hidden md:blockHiddenBlock
md:hiddenVisibleHidden

On mobile, MessagingContactView renders a back button that navigates to the contact list:

messaging_contact_view.rs
Link {
to: Route::MessagingView {},
class: "md:hidden flex items-center gap-1 ...",
ArrowLeft { class: "w-4 h-4" }
span { "Back" }
}

The button uses md:hidden so it only appears below 768px.

Long text and URLs previously overflowed bubble boundaries on narrow screens. The fix applies four changes:

Flex items default to min-width: auto, which prevents shrinking below content size. Adding min-w-0 allows bubbles to shrink:

message_entry_component.rs
div { class: "flex flex-col items-start min-w-0 max-w-[90%] md:max-w-[75%]",

The tooltip component uses inline-flex, which can escape parent bounds. max-w-full constrains it:

tooltip_ui.rs
class: tw_merge!("group/tooltip relative inline-flex max-w-full", props.class)

The communication feed adds overflow-x-hidden to clip any horizontal overflow:

communication_feed_component.rs
div { class: "flex-1 overflow-y-auto overflow-x-hidden",

Text elements inside bubbles use break-words to wrap long URLs and unbroken strings.

The phone and email selectors in the compose bar expand to full width on mobile:

message_compose_component.rs
SearchableSelect { class: "max-w-full md:max-w-xs", ... } // phone selectors
SearchableSelect { class: "max-w-full md:max-w-sm", ... } // email selectors
FileRole
messaging/views/messaging_view.rsContact list + empty state grid
messaging/views/messaging_contact_view.rsConversation view with back button
messaging/components/conversation_sidebar_component.rsSidebar panel (hidden on mobile)
messaging/components/message_entry_component.rsChat bubble rendering
messaging/components/message_compose_component.rsCompose bar with selectors
messaging/components/communication_feed_component.rsFeed container
ui/tooltip_ui.rsTooltip primitive

All files are under src/mods/ in the app source.