| Version | Tag | Status | API |
|---|---|---|---|
| v1 | <oc-chat-bubble-v1> |
Stable, allowed for generation | ChatBubbleV1 |
Overview (v1)
Source: ./src/components/chat-bubble/v1/Overview.mdx
Chat bubble
The chat bubble represents a single message in a chat interface. It can be styled as either a sent or received message, and can display the sender's name and timestamp. The component also allows for customization of background and text colors through CSS variables.
Default variation
Story Default:
<oc-chat-bubble-v1>
<oc-placeholder-v1 style="height: 100px;">DETACH TO REPLACE CONTENT</oc-placeholder-v1>
</oc-chat-bubble-v1>
Configuration
The chat bubble component is available in the main styling variants sent and received.
This component is configurable, allowing you to tailor its features and appearance to your specific needs.
To explore all the available options and adjust the component, use the component configurator and see the changes affect the component in real-time.
Usage guidelines
Before integrating the chat bubble component into your project, make sure you have correctly installed the OTTO components package. Look through the variations page for examples of possible component variations. Here, you can discover both common and specific variations that address different use cases.
Info
See the Chat bubble UX documentation for detailed user experience guidelines.
Accessibility
The chat bubble component does not include built-in accessibility features. Sender names and timestamps are announced as plain text by screen readers before the actual content. Ensure your chat content is properly accessible for your use case.
Configuration (v1)
Source: ./src/components/chat-bubble/v1/Configuration.mdx
Chat bubble V1 configuration
Configure the chat bubble component with the controls below and see the changes live in the preview canvas. Click the Show code button within the preview canvas to see the source code for the current component configuration.
Story Default:
<oc-chat-bubble-v1>
<oc-placeholder-v1 style="height: 100px;">DETACH TO REPLACE CONTENT</oc-placeholder-v1>
</oc-chat-bubble-v1>
Interactive configurator (Storybook controls); every option is listed in the API section of this file.
API v1
Source: ./src/components/chat-bubble/v1/ChatBubbleV1.API.g.mdx
Chat Bubble v1 API
API: <oc-chat-bubble-v1> (ChatBubbleV1)
Chat Bubble is a component that represents a single message in a chat interface. It can be styled as either a sent or received message, and can display the sender's name and timestamp. The component also allows for customization of background and text colors through CSS variables.
Attributes / properties
| Attribute | Type | Default | Required | Description |
|---|---|---|---|---|
variant |
"sent" | "received" |
"sent" |
no | Sets the main styling variant of the chat bubble. |
sender |
string |
undefined |
no | Sets the sender's name, which is displayed above the chat bubble content. |
timestamp |
string |
undefined |
no | Displays the timestamp of the message when it was created, in ISO format (e.g. 2026-01-15T13:37).This string is parsed and formatted depending on the distance to today. |
hide-date |
boolean |
false |
no | Indicates whether the date should be hidden and only the time should be displayed. Set to true to hide the date and show only the time in the timestamp. |
Slots
| Slot | Required | Description |
|---|---|---|
default |
yes | Sets the main content of the chat bubble. |
Events
| Event | Detail type | Description |
|---|---|---|
oc-property-change |
OcChatBubbleV1Events["oc-property-change"] |
Whenever a property value changes, this event triggers. Use this event to track all property changes within the component. Refer to the Events documentation for more information. |
oc-mount |
{ component: string; } |
Fired when the component is mounted to the DOM. The event is fired when the onMount hook of the component is called by the runtime. |
oc-unmount |
{ component: string; } |
Fired when the component is unmounted from the DOM. The event is fired when the function returned by the onMount hook of the component is called by the runtime. |
CSS custom properties
| Custom property | Default | Description |
|---|---|---|
--background-color |
undefined |
Sets a custom background color through a CSS variable. Note: The preferred way of using colors is via Design Tokens instead of hex values. |
--text-color |
undefined |
Sets a custom text color through a CSS variable. Note: The preferred way of using colors is via Design Tokens instead of hex values. |
--custom-spacing-x |
undefined |
Sets the custom horizontal spacing of the chat bubble. |
--custom-spacing-y |
undefined |
Sets the custom vertical spacing of the chat bubble. |
--border-radius |
undefined |
Sets the custom border radius of the chat bubble. |
Variations (v1)
Source: ./src/components/chat-bubble/v1/Variations.mdx
Variations
Listed below are the most common variations of the chat bubble component as well as specific component variations for different use cases.
You can explore all available options using the component configurator, adjust the component to your needs, and see the changes live in a preview canvas.
Default
Story: components-chat-bubble-variations--default · tags: components, chat-bubble, 1, variations
The default chat bubble component uses the sent variant that aligns the bubble to the right.
Args: defaultSlot=<oc-placeholder-v1 style="height: 100px;">DETACH TO REPLACE CONTENT</oc-placeholder-v1>
<oc-chat-bubble-v1>
<oc-placeholder-v1 style="height: 100px;">DETACH TO REPLACE CONTENT</oc-placeholder-v1>
</oc-chat-bubble-v1>
Received
Story: components-chat-bubble-variations--received · tags: components, chat-bubble, 1, variations
The received variant aligns the bubble to the left.
Args: defaultSlot=<oc-placeholder-v1 style="height: 100px;">DETACH TO REPLACE CONTENT</oc-placeholder-v1>, variant=received
<oc-chat-bubble-v1 variant="received">
<oc-placeholder-v1 style="height: 100px;">DETACH TO REPLACE CONTENT</oc-placeholder-v1>
</oc-chat-bubble-v1>
Received with sender and timestamp
Story: components-chat-bubble-variations--received-with-sender-and-timestamp · tags: components, chat-bubble, 1, variations
The received variant with sender and timestamp.
Args: defaultSlot=<oc-placeholder-v1 style="height: 100px;">DETACH TO REPLACE CONTENT</oc-placeholder-v1>, variant=received, sender=Absender, timestamp=2026-01-01T01:01
<oc-chat-bubble-v1 variant="received" sender="Absender" timestamp="2026-01-01T01:01">
<oc-placeholder-v1 style="height: 100px;">DETACH TO REPLACE CONTENT</oc-placeholder-v1>
</oc-chat-bubble-v1>
Demo: Custom background color
Story: components-chat-bubble-variations--demo-custom-background-color · tags: components, chat-bubble, 1, variations
Demo: Custom background color
<oc-chat-bubble-v1
variant="received"
sender="Absender"
timestamp="2026-01-01T12:34"
style="--background-color: var(--oc-semantic-color-background-soft-mint)"
>Hier steht ein sehr langer Probetext über zwei beste Freunde, die einen tollen Chat-Verlauf
haben.</oc-chat-bubble-v1
>
Story source (TypeScript, verbatim from Storybook)
{
name: "Demo: Custom background color",
parameters: {
controls: {
disabled: true
},
chromatic: {
hideInChromatic: true
}
},
argTypes: hideControlsBadge(Metadata),
render() {
return html`
<oc-chat-bubble-v1
variant="received"
sender="Absender"
timestamp="2026-01-01T12:34"
style="--background-color: var(--oc-semantic-color-background-soft-mint)"
>Hier steht ein sehr langer Probetext über zwei beste Freunde, die einen tollen Chat-Verlauf
haben.</oc-chat-bubble-v1
>
`;
}
}
Demo: Custom background color and text color
Story: components-chat-bubble-variations--demo-custom-background-color-and-text-color · tags: components, chat-bubble, 1, variations
Demo: Custom background color and text color
<oc-chat-bubble-v1
variant="received"
sender="Absender"
timestamp="2026-01-01T12:34"
style="--background-color: var(--oc-semantic-color-background-strong-blue); --text-color: var(--oc-semantic-color-text-inverted)"
>Hier steht ein sehr langer Probetext über zwei beste Freunde, die einen tollen Chat-Verlauf
haben.</oc-chat-bubble-v1
>
Story source (TypeScript, verbatim from Storybook)
{
name: "Demo: Custom background color and text color",
parameters: {
controls: {
disabled: true
},
chromatic: {
hideInChromatic: true
}
},
argTypes: hideControlsBadge(Metadata),
render() {
return html`
<oc-chat-bubble-v1
variant="received"
sender="Absender"
timestamp="2026-01-01T12:34"
style="--background-color: var(--oc-semantic-color-background-strong-blue); --text-color: var(--oc-semantic-color-text-inverted)"
>Hier steht ein sehr langer Probetext über zwei beste Freunde, die einen tollen Chat-Verlauf
haben.</oc-chat-bubble-v1
>
`;
}
}
Demo: Chat flow
Story: components-chat-bubble-variations--demo-chat-flow · tags: components, chat-bubble, 1, variations
Demo: Chat flow with sent and received messages
<style>
.chat-wrapper {
max-width: 800px;
margin: 0 auto;
padding: 24px;
background: #f5f5f5;
border-radius: 8px;
display: flex;
flex-direction: column;
gap: 16px;
}
.chat-wrapper p {
margin: 0;
}
</style>
<div class="chat-wrapper">
<oc-chat-bubble-v1
variant="received"
sender="Otto Shopping AI"
timestamp="${messageTimestamps[0]}"
>
<p>Hallo! Ich bin Ihr Otto Shopping Assistent. Wie kann ich Ihnen heute helfen?</p>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1 variant="sent" sender="Anna M." timestamp="${messageTimestamps[1]}">
<p>Hallo! Ich suche eine neue Waschmaschine für einen 2-Personen-Haushalt.</p>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1
variant="received"
sender="Otto Shopping AI"
timestamp="${messageTimestamps[2]}"
>
<p>
Perfekt! Für einen 2-Personen-Haushalt empfehle ich eine Waschmaschine mit 7-8 kg
Fassungsvermögen. Haben Sie besondere Anforderungen? Zum Beispiel:
</p>
<ul>
<li>Energieeffizienzklasse</li>
<li>Spezielle Programme (z.B. Schnellwäsche, Eco-Modus)</li>
<li>Budget</li>
</ul>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1 variant="sent" sender="Anna M." timestamp="${messageTimestamps[3]}">
<p>
Am wichtigsten ist mir eine gute Energieeffizienzklasse. Mein Budget liegt bei etwa 500
Euro.
</p>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1
variant="received"
sender="Otto Shopping AI"
timestamp="${messageTimestamps[4]}"
>
<p>
Ausgezeichnet! Ich habe 3 passende Modelle mit Energieeffizienzklasse A für Sie
gefunden:
</p>
<p><strong>1. Bosch Serie 6 WAU28T40</strong> - 8kg, A-Klasse, 1400 U/min - 479€</p>
<p><strong>2. Siemens WM14N190</strong> - 7kg, A-Klasse, 1400 U/min - 449€</p>
<p><strong>3. Miele WSD 023 WCS</strong> - 8kg, A-Klasse, 1400 U/min - 499€</p>
<p>Welches Modell interessiert Sie am meisten?</p>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1 variant="sent" sender="Anna M." timestamp="${messageTimestamps[5]}">
<p>Die Bosch Serie 6 klingt interessant. Wie sind die Bewertungen?</p>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1
variant="received"
sender="Otto Shopping AI"
timestamp="${messageTimestamps[6]}"
>
<p>
Die Bosch Serie 6 WAU28T40 hat hervorragende Bewertungen! ⭐⭐⭐⭐⭐ 4.7 von 5 Sternen
(824 Bewertungen)
</p>
<p>Kunden loben besonders:</p>
<ul>
<li>Sehr leiser Betrieb</li>
<li>Gute Waschleistung</li>
<li>SpeedPerfect-Funktion spart Zeit</li>
<li>Niedriger Energie- und Wasserverbrauch</li>
</ul>
<p>Möchten Sie die Maschine in den Warenkorb legen?</p>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1 variant="sent" sender="Anna M." timestamp="${messageTimestamps[7]}">
<p>Ja, bitte!</p>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1
variant="received"
sender="Otto Shopping AI"
timestamp="${messageTimestamps[8]}"
>
<p>Perfekt! Die Waschmaschine wurde in Ihren Warenkorb gelegt. 🛒</p>
<p>
Gute Nachrichten: Aktuell ist die Lieferung und der Altgeräte-Abtransport kostenlos! Die
Lieferung erfolgt innerhalb von 3-5 Werktagen.
</p>
<p>Kann ich Ihnen sonst noch weiterhelfen?</p>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1 variant="sent" sender="Anna M." timestamp="${messageTimestamps[9]}">
<p>Nein, danke! Das war sehr hilfreich. 😊</p>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1
variant="received"
sender="Otto Shopping AI"
timestamp="${messageTimestamps[10]}"
>
<p>
Sehr gerne! Viel Freude mit Ihrer neuen Waschmaschine. Bei Fragen stehe ich jederzeit
zur Verfügung. Schönen Tag noch! 👋
</p>
</oc-chat-bubble-v1>
</div>
Story source (TypeScript, verbatim from Storybook)
{
name: "Demo: Chat flow",
parameters: {
controls: {
disabled: true
},
chromatic: {
hideInChromatic: true
}
},
argTypes: hideControlsBadge(Metadata),
render() {
const now = new Date();
const messageTimestamps = Array.from({
length: 11
}, (_, index) => {
const date = new Date(now);
date.setDate(now.getDate() - (10 - index));
return date.toISOString().slice(0, 16);
});
return html`
<style>
.chat-wrapper {
max-width: 800px;
margin: 0 auto;
padding: 24px;
background: #f5f5f5;
border-radius: 8px;
display: flex;
flex-direction: column;
gap: 16px;
}
.chat-wrapper p {
margin: 0;
}
</style>
<div class="chat-wrapper">
<oc-chat-bubble-v1
variant="received"
sender="Otto Shopping AI"
timestamp="${messageTimestamps[0]}"
>
<p>Hallo! Ich bin Ihr Otto Shopping Assistent. Wie kann ich Ihnen heute helfen?</p>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1 variant="sent" sender="Anna M." timestamp="${messageTimestamps[1]}">
<p>Hallo! Ich suche eine neue Waschmaschine für einen 2-Personen-Haushalt.</p>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1
variant="received"
sender="Otto Shopping AI"
timestamp="${messageTimestamps[2]}"
>
<p>
Perfekt! Für einen 2-Personen-Haushalt empfehle ich eine Waschmaschine mit 7-8 kg
Fassungsvermögen. Haben Sie besondere Anforderungen? Zum Beispiel:
</p>
<ul>
<li>Energieeffizienzklasse</li>
<li>Spezielle Programme (z.B. Schnellwäsche, Eco-Modus)</li>
<li>Budget</li>
</ul>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1 variant="sent" sender="Anna M." timestamp="${messageTimestamps[3]}">
<p>
Am wichtigsten ist mir eine gute Energieeffizienzklasse. Mein Budget liegt bei etwa 500
Euro.
</p>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1
variant="received"
sender="Otto Shopping AI"
timestamp="${messageTimestamps[4]}"
>
<p>
Ausgezeichnet! Ich habe 3 passende Modelle mit Energieeffizienzklasse A für Sie
gefunden:
</p>
<p><strong>1. Bosch Serie 6 WAU28T40</strong> - 8kg, A-Klasse, 1400 U/min - 479€</p>
<p><strong>2. Siemens WM14N190</strong> - 7kg, A-Klasse, 1400 U/min - 449€</p>
<p><strong>3. Miele WSD 023 WCS</strong> - 8kg, A-Klasse, 1400 U/min - 499€</p>
<p>Welches Modell interessiert Sie am meisten?</p>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1 variant="sent" sender="Anna M." timestamp="${messageTimestamps[5]}">
<p>Die Bosch Serie 6 klingt interessant. Wie sind die Bewertungen?</p>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1
variant="received"
sender="Otto Shopping AI"
timestamp="${messageTimestamps[6]}"
>
<p>
Die Bosch Serie 6 WAU28T40 hat hervorragende Bewertungen! ⭐⭐⭐⭐⭐ 4.7 von 5 Sternen
(824 Bewertungen)
</p>
<p>Kunden loben besonders:</p>
<ul>
<li>Sehr leiser Betrieb</li>
<li>Gute Waschleistung</li>
<li>SpeedPerfect-Funktion spart Zeit</li>
<li>Niedriger Energie- und Wasserverbrauch</li>
</ul>
<p>Möchten Sie die Maschine in den Warenkorb legen?</p>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1 variant="sent" sender="Anna M." timestamp="${messageTimestamps[7]}">
<p>Ja, bitte!</p>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1
variant="received"
sender="Otto Shopping AI"
timestamp="${messageTimestamps[8]}"
>
<p>Perfekt! Die Waschmaschine wurde in Ihren Warenkorb gelegt. 🛒</p>
<p>
Gute Nachrichten: Aktuell ist die Lieferung und der Altgeräte-Abtransport kostenlos! Die
Lieferung erfolgt innerhalb von 3-5 Werktagen.
</p>
<p>Kann ich Ihnen sonst noch weiterhelfen?</p>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1 variant="sent" sender="Anna M." timestamp="${messageTimestamps[9]}">
<p>Nein, danke! Das war sehr hilfreich. 😊</p>
</oc-chat-bubble-v1>
<oc-chat-bubble-v1
variant="received"
sender="Otto Shopping AI"
timestamp="${messageTimestamps[10]}"
>
<p>
Sehr gerne! Viel Freude mit Ihrer neuen Waschmaschine. Bei Fragen stehe ich jederzeit
zur Verfügung. Schönen Tag noch! 👋
</p>
</oc-chat-bubble-v1>
</div>
`;
}
}
Demo: Custom spacings
Story: components-chat-bubble-variations--demo-custom-spacings · tags: components, chat-bubble, 1, variations
Demo of a chat bubble component containing a custom layout with adjustable sliders for custom spacings.
<div style="display: flex; width: fit-content; ">
<oc-chat-bubble-v1>
<h1 class="oc-headline-200 oc-text-color-success">Hallo Sophie,</h1>
<h1 class="oc-headline-100 oc-text-color-success">wie kann ich dir helfen?</h1>
</oc-chat-bubble-v1>
</div>
<div style="display: flex; flex-direction: column; gap: 16px; margin-top: 32px;">
<div style="display: flex; gap: 16px; align-items: center;">
<label for="horizontal-slider">Horizontal Spacing</label>
<input
type="range"
name="horizontal-slider"
id="horizontal-slider"
min="0"
max="64"
value="0"
/>
<span id="horizontal-slider-value">0px</span>
</div>
<div style="display: flex; gap: 16px; align-items: center;">
<label for="vertical-slider">Vertical Spacing</label>
<input
type="range"
name="vertical-slider"
id="vertical-slider"
min="0"
max="64"
value="16"
/>
<span id="vertical-slider-value">16px</span>
</div>
</div>
<script>
(() => {
const row = document.querySelector("oc-chat-bubble-v1");
const horizontalSlider = document.getElementById("horizontal-slider");
const horizontalSliderValue = document.getElementById("horizontal-slider-value");
const verticalSlider = document.getElementById("vertical-slider");
const verticalSliderValue = document.getElementById("vertical-slider-value");
horizontalSlider.addEventListener("input", (event) => {
const value = event.target.value + "px";
row.style.setProperty("--custom-spacing-x", value);
horizontalSliderValue.textContent = value;
});
verticalSlider.addEventListener("input", (event) => {
const value = event.target.value + "px";
row.style.setProperty("--custom-spacing-y", value);
verticalSliderValue.textContent = value;
});
})();
</script>
Story source (TypeScript, verbatim from Storybook)
{
name: "Demo: Custom spacings",
parameters: {
controls: {
disabled: true
},
backgrounds: {
value: "frame"
},
chromatic: {
hideInChromatic: true
}
},
render: () => {
return html`
<div style="display: flex; width: fit-content; ">
<oc-chat-bubble-v1>
<h1 class="oc-headline-200 oc-text-color-success">Hallo Sophie,</h1>
<h1 class="oc-headline-100 oc-text-color-success">wie kann ich dir helfen?</h1>
</oc-chat-bubble-v1>
</div>
<div style="display: flex; flex-direction: column; gap: 16px; margin-top: 32px;">
<div style="display: flex; gap: 16px; align-items: center;">
<label for="horizontal-slider">Horizontal Spacing</label>
<input
type="range"
name="horizontal-slider"
id="horizontal-slider"
min="0"
max="64"
value="0"
/>
<span id="horizontal-slider-value">0px</span>
</div>
<div style="display: flex; gap: 16px; align-items: center;">
<label for="vertical-slider">Vertical Spacing</label>
<input
type="range"
name="vertical-slider"
id="vertical-slider"
min="0"
max="64"
value="16"
/>
<span id="vertical-slider-value">16px</span>
</div>
</div>
<script>
(() => {
const row = document.querySelector("oc-chat-bubble-v1");
const horizontalSlider = document.getElementById("horizontal-slider");
const horizontalSliderValue = document.getElementById("horizontal-slider-value");
const verticalSlider = document.getElementById("vertical-slider");
const verticalSliderValue = document.getElementById("vertical-slider-value");
horizontalSlider.addEventListener("input", (event) => {
const value = event.target.value + "px";
row.style.setProperty("--custom-spacing-x", value);
horizontalSliderValue.textContent = value;
});
verticalSlider.addEventListener("input", (event) => {
const value = event.target.value + "px";
row.style.setProperty("--custom-spacing-y", value);
verticalSliderValue.textContent = value;
});
})();
</script>
`;
},
argTypes: hideControlsBadge(Metadata)
}