diff --git a/dev/messages-ai-chat.html b/dev/messages-ai-chat.html
new file mode 100644
index 00000000000..a8e92a54b29
--- /dev/null
+++ b/dev/messages-ai-chat.html
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+ Messages AI Chat
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/message-list/package.json b/packages/message-list/package.json
index cb180cf64c1..34ecf01b550 100644
--- a/packages/message-list/package.json
+++ b/packages/message-list/package.json
@@ -42,6 +42,7 @@
"@vaadin/a11y-base": "24.8.0-alpha15",
"@vaadin/avatar": "24.8.0-alpha15",
"@vaadin/component-base": "24.8.0-alpha15",
+ "@vaadin/markdown": "24.8.0-alpha15",
"@vaadin/vaadin-lumo-styles": "24.8.0-alpha15",
"@vaadin/vaadin-material-styles": "24.8.0-alpha15",
"@vaadin/vaadin-themable-mixin": "24.8.0-alpha15",
diff --git a/packages/message-list/src/vaadin-message-list-mixin.d.ts b/packages/message-list/src/vaadin-message-list-mixin.d.ts
index 7c95dd0396a..03b8ea86e36 100644
--- a/packages/message-list/src/vaadin-message-list-mixin.d.ts
+++ b/packages/message-list/src/vaadin-message-list-mixin.d.ts
@@ -39,4 +39,9 @@ export declare class MessageListMixinClass {
* ```
*/
items: MessageListItem[] | null | undefined;
+
+ /**
+ * When set to `true`, the message text is parsed as Markdown.
+ */
+ markdown: boolean | undefined;
}
diff --git a/packages/message-list/src/vaadin-message-list-mixin.js b/packages/message-list/src/vaadin-message-list-mixin.js
index c4d075ac97f..c24061ee2ef 100644
--- a/packages/message-list/src/vaadin-message-list-mixin.js
+++ b/packages/message-list/src/vaadin-message-list-mixin.js
@@ -3,6 +3,7 @@
* Copyright (c) 2021 - 2025 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
+import '@vaadin/markdown/src/vaadin-markdown.js';
import { html, render } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';
import { KeyboardDirectionMixin } from '@vaadin/a11y-base/src/keyboard-direction-mixin.js';
@@ -37,6 +38,16 @@ export const MessageListMixin = (superClass) =>
observer: '_itemsChanged',
sync: true,
},
+
+ /**
+ * When set to `true`, the message text is parsed as Markdown.
+ * @type {boolean}
+ */
+ markdown: {
+ type: Boolean,
+ observer: '__markdownChanged',
+ reflectToAttribute: true,
+ },
};
}
@@ -86,6 +97,11 @@ export const MessageListMixin = (superClass) =>
}
}
+ /** @private */
+ __markdownChanged(_markdown) {
+ this._renderMessages(this.items);
+ }
+
/** @private */
_renderMessages(items) {
render(
@@ -102,7 +118,9 @@ export const MessageListMixin = (superClass) =>
theme="${ifDefined(item.theme)}"
class="${ifDefined(item.className)}"
@focusin="${this._onMessageFocusIn}"
- >${item.text}${this.markdown
+ ? html``
+ : item.text}
`,
)}
diff --git a/packages/message-list/src/vaadin-message-styles.js b/packages/message-list/src/vaadin-message-styles.js
index fee40b88bae..36be2029d4c 100644
--- a/packages/message-list/src/vaadin-message-styles.js
+++ b/packages/message-list/src/vaadin-message-styles.js
@@ -40,4 +40,8 @@ export const messageStyles = css`
--vaadin-avatar-outline-width: 0;
flex-shrink: 0;
}
+
+ ::slotted(vaadin-markdown) {
+ white-space: normal;
+ }
`;
diff --git a/packages/message-list/test/message-list-markdown.test.js b/packages/message-list/test/message-list-markdown.test.js
new file mode 100644
index 00000000000..b1587541c0c
--- /dev/null
+++ b/packages/message-list/test/message-list-markdown.test.js
@@ -0,0 +1,53 @@
+import { expect } from '@vaadin/chai-plugins';
+import { fixtureSync, nextUpdate } from '@vaadin/testing-helpers';
+import '../src/vaadin-message-list.js';
+
+describe('message-list-markdown', () => {
+ let messageList;
+ const messages = [
+ {
+ text: 'This is a **bold text** in Markdown',
+ time: '10:00 AM',
+ userName: 'Markdown User',
+ userAbbr: 'MU',
+ },
+ ];
+
+ beforeEach(async () => {
+ messageList = fixtureSync('');
+ messageList.items = messages;
+ await nextUpdate(messageList);
+ });
+
+ it('should render the message items as markdown', () => {
+ const strongElement = messageList.querySelector('vaadin-message strong');
+ expect(strongElement).to.exist;
+ expect(strongElement.textContent).to.equal('bold text');
+ });
+
+ it('should toggle markdown rendering when property changes', async () => {
+ // First check with markdown enabled
+ expect(messageList.querySelector('vaadin-message strong')).to.exist;
+
+ // Disable markdown
+ messageList.markdown = false;
+ await nextUpdate(messageList);
+
+ // Verify markdown is disabled on messages
+ expect(messageList.querySelector('vaadin-message strong')).to.not.exist;
+
+ // Re-enable markdown
+ messageList.markdown = true;
+ await nextUpdate(messageList);
+
+ // Verify markdown is re-enabled
+ expect(messageList.querySelector('vaadin-message strong')).to.exist;
+ });
+
+ it('should toggle markdown attribute', async () => {
+ expect(messageList.hasAttribute('markdown')).to.be.true;
+ messageList.markdown = false;
+ await nextUpdate(messageList);
+ expect(messageList.hasAttribute('markdown')).to.be.false;
+ });
+});
diff --git a/packages/message-list/test/typings/message-list.types.ts b/packages/message-list/test/typings/message-list.types.ts
index d5338ef1aca..9f329923fe0 100644
--- a/packages/message-list/test/typings/message-list.types.ts
+++ b/packages/message-list/test/typings/message-list.types.ts
@@ -12,6 +12,7 @@ const list = document.createElement('vaadin-message-list');
// Properties
assertType(list.items);
+assertType(list.markdown);
// Item properties
const item: MessageListItem = list.items ? list.items[0] : {};
diff --git a/packages/message-list/test/visual/lumo/message-list.test.js b/packages/message-list/test/visual/lumo/message-list.test.js
index a7f5fa350aa..46b5fa605a5 100644
--- a/packages/message-list/test/visual/lumo/message-list.test.js
+++ b/packages/message-list/test/visual/lumo/message-list.test.js
@@ -59,6 +59,13 @@ describe('message-list', () => {
await sendKeys({ press: 'ArrowDown' });
await visualDiff(div, `${dir}-focused`);
});
+
+ it('markdown', async () => {
+ element.items[0].text = 'This is a **bold text** in Markdown';
+ element.items = [...element.items];
+ element.markdown = true;
+ await visualDiff(div, `${dir}-markdown`);
+ });
});
});
});
diff --git a/packages/message-list/test/visual/lumo/screenshots/message-list/baseline/ltr-markdown.png b/packages/message-list/test/visual/lumo/screenshots/message-list/baseline/ltr-markdown.png
new file mode 100644
index 00000000000..2ca61ff1fb5
Binary files /dev/null and b/packages/message-list/test/visual/lumo/screenshots/message-list/baseline/ltr-markdown.png differ
diff --git a/packages/message-list/test/visual/lumo/screenshots/message-list/baseline/rtl-markdown.png b/packages/message-list/test/visual/lumo/screenshots/message-list/baseline/rtl-markdown.png
new file mode 100644
index 00000000000..6dff6396446
Binary files /dev/null and b/packages/message-list/test/visual/lumo/screenshots/message-list/baseline/rtl-markdown.png differ
diff --git a/packages/message-list/test/visual/material/message-list.test.js b/packages/message-list/test/visual/material/message-list.test.js
index c6ab3201d9b..5789b5ad2e6 100644
--- a/packages/message-list/test/visual/material/message-list.test.js
+++ b/packages/message-list/test/visual/material/message-list.test.js
@@ -59,6 +59,13 @@ describe('message-list', () => {
await sendKeys({ press: 'ArrowDown' });
await visualDiff(div, `${dir}-focused`);
});
+
+ it('markdown', async () => {
+ element.items[0].text = 'This is a **bold text** in Markdown';
+ element.items = [...element.items];
+ element.markdown = true;
+ await visualDiff(div, `${dir}-markdown`);
+ });
});
});
});
diff --git a/packages/message-list/test/visual/material/screenshots/message-list/baseline/ltr-markdown.png b/packages/message-list/test/visual/material/screenshots/message-list/baseline/ltr-markdown.png
new file mode 100644
index 00000000000..f191b613823
Binary files /dev/null and b/packages/message-list/test/visual/material/screenshots/message-list/baseline/ltr-markdown.png differ
diff --git a/packages/message-list/test/visual/material/screenshots/message-list/baseline/rtl-markdown.png b/packages/message-list/test/visual/material/screenshots/message-list/baseline/rtl-markdown.png
new file mode 100644
index 00000000000..5442e638031
Binary files /dev/null and b/packages/message-list/test/visual/material/screenshots/message-list/baseline/rtl-markdown.png differ
diff --git a/packages/message-list/theme/lumo/vaadin-message-list.js b/packages/message-list/theme/lumo/vaadin-message-list.js
index 8b8d5115866..42b10a9050c 100644
--- a/packages/message-list/theme/lumo/vaadin-message-list.js
+++ b/packages/message-list/theme/lumo/vaadin-message-list.js
@@ -1,2 +1,3 @@
+import '@vaadin/markdown/theme/lumo/vaadin-markdown.js';
import './vaadin-message-list-styles.js';
import '../../src/vaadin-message-list.js';
diff --git a/packages/message-list/theme/material/vaadin-message-list.js b/packages/message-list/theme/material/vaadin-message-list.js
index 8b8d5115866..d2f65635b0a 100644
--- a/packages/message-list/theme/material/vaadin-message-list.js
+++ b/packages/message-list/theme/material/vaadin-message-list.js
@@ -1,2 +1,3 @@
+import '@vaadin/markdown/theme/material/vaadin-markdown.js';
import './vaadin-message-list-styles.js';
import '../../src/vaadin-message-list.js';