Chat - Tailwind CSS
Style chat components using Tailwind CSS utility classes with the structural primitives from @mui/x-chat.
@mui/x-chat ships structural chat primitives with zero built-in styles.
Each component renders semantic HTML elements with data-* attributes that reflect component state, making them a natural fit for Tailwind CSS utility classes.
Installation
Install the package alongside Tailwind:
npm install @mui/x-chatNamespace API
Structural primitives are available as namespace exports for clean dot-notation usage:
import {
Chat,
Composer,
Message,
MessageList,
Conversation,
ConversationList,
Indicators,
} from '@mui/x-chat';
// Usage
<Chat.Root>
<Chat.Layout>
<MessageList.Root renderItem={...} />
<Composer.Root>
<Composer.TextArea />
<Composer.Toolbar>
<Composer.AttachButton />
<Composer.SendButton />
</Composer.Toolbar>
</Composer.Root>
</Chat.Layout>
</Chat.Root>
Applying Tailwind classes
Pass className to any primitive component:
<Composer.Root className="flex flex-col gap-1 border-t border-gray-200 p-3 bg-white">
<Composer.TextArea
className="resize-none rounded-lg border border-gray-300 px-3 py-2 text-sm
focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
<Composer.Toolbar className="flex items-center justify-end gap-2">
<Composer.AttachButton className="rounded p-1.5 text-gray-500 hover:bg-gray-100" />
<Composer.SendButton
className="rounded-lg bg-blue-600 px-3 py-1.5 text-sm font-medium text-white
hover:bg-blue-700 disabled:opacity-40"
/>
</Composer.Toolbar>
</Composer.Root>
Data attributes
Every primitive component exposes data-* attributes that reflect its current state.
Use Tailwind's attribute selectors to style state variations without JavaScript:
{
/* The send button sets data-disabled when the composer is empty or streaming */
}
<Composer.SendButton className="bg-blue-600 text-white data-[disabled]:opacity-40 data-[disabled]:cursor-not-allowed" />;
{
/* Message root sets data-author="self" or data-author="other" */
}
<Message.Root className="flex gap-3 data-[author=self]:flex-row-reverse" />;
{
/* Typing indicator sets data-visible when the assistant is responding */
}
<Indicators.TypingIndicator className="hidden data-[visible]:flex items-center gap-1 text-sm text-gray-500" />;
Common data attributes
| Component | Attribute | Values | Description |
|---|---|---|---|
Message.Root |
data-author |
"self", "other" |
Current user vs. other participants |
Message.Root |
data-status |
"sending", "sent", "error" |
Message delivery status |
Composer.SendButton |
data-disabled |
present / absent | Empty input or streaming |
Composer.Root |
data-streaming |
present / absent | Response in progress |
ConversationList.Item |
data-active |
present / absent | Currently selected conversation |
Slot props for custom elements
Use the slots and slotProps props to replace inner elements while keeping behavior intact:
<MessageList.Root
slots={{
messageListContent: 'div',
}}
slotProps={{
messageListContent: {
className: 'flex flex-col gap-2 p-4',
},
}}
renderItem={({ id }) => <MyMessage key={id} id={id} />}
/>
Complete demo: chat shell
The following interactive demo shows a fully functional chat styled entirely with Tailwind CSS utility classes, using the structural primitives from @mui/x-chat: