DevExtreme v26.1 is now available.

Explore our newest features/capabilities and share your thoughts with us.

Your search did not match any results.

JavaScript/jQuery Chat - Prompt Suggestions

DevExtreme JavaScript Chat supports suggestions - hints that guide users throughout conversations. The component displays suggestion buttons above the message input field and supports both persistent and temporary hints.

Backend API
$(() => { const store = []; const messages = [ { role: 'system', content: SYSTEM_PROMPT }, ]; DevExpress.localization.loadMessages({ en: { 'dxChat-emptyListMessage': 'Chat is Empty', 'dxChat-emptyListPrompt': 'Your Shopping AI Assistant is ready to help. Ask a question or choose one of the suggested prompts to get started.', 'dxChat-textareaPlaceholder': 'Ask AI Assistant...', }, }); const chatService = new AzureOpenAI({ dangerouslyAllowBrowser: true, deployment, endpoint, apiVersion, apiKey, }); async function getAIResponse(messages) { const params = { messages, model: deployment, max_completion_tokens: 1000, temperature: 0.7, }; const response = await chatService.chat.completions.create(params); const data = { choices: response.choices }; return data.choices[0].message?.content; } function alertLimitReached() { instance.option({ alerts: [{ message: 'Request limit reached, try again in a minute.', }], }); setTimeout(() => { instance.option({ alerts: [] }); }, ALERT_TIMEOUT); } function toggleDisabledState(disabled, event) { isDisabled = disabled; instance.option({ suggestions: { disabled } }); instance.element().toggleClass(CHAT_DISABLED_CLASS, disabled); if (disabled) { event?.target.blur(); } else { event?.target.focus(); } } async function processMessageSending(message, event) { toggleDisabledState(true, event); messages.push({ role: 'user', content: message.text }); instance.option({ typingUsers: [assistant] }); try { const aiResponse = await getAIResponse(messages); setTimeout(() => { instance.option({ typingUsers: [] }); messages.push({ role: 'assistant', content: aiResponse }); renderAssistantMessage(aiResponse); }, 200); } catch { instance.option({ typingUsers: [] }); messages.pop(); alertLimitReached(); } finally { toggleDisabledState(false, event); } } function renderAssistantMessage(text) { const message = { id: Date.now(), timestamp: new Date(), author: assistant, text, }; dataSource.store().push([{ type: 'insert', data: message }]); } function convertToHtml(value) { const result = unified() .use(remarkParse) .use(remarkRehype) .use(rehypeMinifyWhitespace) .use(rehypeStringify) .processSync(value) .toString(); return result; } function renderMessageContent(message, element) { $('<div>') .addClass('chat-messagebubble-text') .html(convertToHtml(message.text)) .appendTo(element); } const customStore = new DevExpress.data.CustomStore({ key: 'id', load: () => { const d = $.Deferred(); setTimeout(() => { d.resolve([...store]); }); return d.promise(); }, insert: (message) => { const d = $.Deferred(); setTimeout(() => { store.push(message); d.resolve(); }); return d.promise(); }, }); const dataSource = new DevExpress.data.DataSource({ store: customStore, paginate: false, }); let isDisabled = false; let sendImmediately = false; let hideAfterUse = false; const suggestions = { items: suggestionItems, onItemClick(e) { const { prompt, text } = e.itemData; if (hideAfterUse) { const currentSuggestions = instance.option('suggestions'); instance.option('suggestions', { items: currentSuggestions.items.filter((item) => item.text !== text) }); } if (sendImmediately) { const message = { id: Date.now(), timestamp: new Date(), author: user, text: prompt }; dataSource.store().push([{ type: 'insert', data: message }]); if (!instance.option('alerts').length) { processMessageSending(message); } } else { instance.option('inputFieldText', prompt); } }, }; const instance = $('#dx-ai-chat').dxChat({ user, height: 520, dataSource, reloadOnChange: false, showAvatar: false, showDayHeaders: false, speechToTextEnabled: true, suggestions, onMessageEntered: (e) => { if (isDisabled) return; const { message, event } = e; dataSource.store().push([{ type: 'insert', data: { id: Date.now(), ...message } }]); if (!instance.option('alerts').length) { processMessageSending(message, event); } }, messageTemplate: (data, element) => { const { message } = data; renderMessageContent(message, element); }, }).dxChat('instance'); $('#send-immediately').dxSwitch({ value: sendImmediately, onValueChanged(e) { sendImmediately = e.value; }, }); $('#hide-after-use').dxSwitch({ value: hideAfterUse, onValueChanged(e) { hideAfterUse = e.value; }, }); });
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> <head> <title>DevExtreme Demo</title> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" /> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script>window.jQuery || document.write(decodeURIComponent('%3Cscript src="js/jquery.min.js"%3E%3C/script%3E'))</script> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/26.1.3/css/dx.light.css" /> <script type="module"> import { AzureOpenAI } from "https://esm.sh/openai@4.73.1"; import { unified } from "https://esm.sh/unified@11?bundle"; import remarkParse from "https://esm.sh/remark-parse@11?bundle"; import remarkRehype from "https://esm.sh/remark-rehype@11?bundle"; import rehypeStringify from "https://esm.sh/rehype-stringify@10?bundle"; import rehypeMinifyWhitespace from "https://esm.sh/rehype-minify-whitespace@6?bundle"; window.AzureOpenAI = AzureOpenAI; window.unified = unified; window.remarkParse = remarkParse; window.remarkRehype = remarkRehype; window.rehypeMinifyWhitespace = rehypeMinifyWhitespace; window.rehypeStringify = rehypeStringify; </script> <script src="js/dx.all.js?v=26.1.3"></script> <script src="data.js"></script> <link rel="stylesheet" type="text/css" href="styles.css" /> <script src="index.js"></script> </head> <body class="dx-viewport"> <div class="demo-container"> <div id="dx-ai-chat"></div> <div class="options"> <div class="caption">Suggestion Options</div> <div class="suggestions-options"> <div class="option"> <div id="send-immediately"></div> <span>Send Immediately</span> </div> <div class="option"> <div id="hide-after-use"></div> <span>Hide After Use</span> </div> </div> </div> </div> </body> </html>
.demo-container { display: flex; flex-direction: column; align-items: center; gap: 20px; } .options { padding: 20px; display: flex; flex-direction: column; min-width: 280px; background-color: rgba(191, 191, 191, 0.15); gap: 16px; width: 100%; max-width: 900px; box-sizing: border-box; } .suggestions-options { display: flex; align-items: center; gap: 24px; } .option { display: flex; align-items: center; gap: 8px; } .caption { font-size: var(--dx-font-size-sm); font-weight: 500; } .dx-chat { max-width: 900px; } .dx-chat-messagelist-empty-image { display: none; } .dx-chat-messagelist-empty-message { font-size: var(--dx-font-size-heading-5); } .dx-chat-messagelist-empty-prompt { max-width: 462px; line-height: 20px; } .dx-chat-messagebubble-content, .chat-messagebubble-text { display: flex; flex-direction: column; } .dx-chat-messagebubble-content > div > p:first-child { margin-top: 0; } .dx-chat-messagebubble-content > div > p:last-child { margin-bottom: 0; } .dx-chat-messagebubble-content h1, .dx-chat-messagebubble-content h2, .dx-chat-messagebubble-content h3, .dx-chat-messagebubble-content h4, .dx-chat-messagebubble-content h5, .dx-chat-messagebubble-content h6 { font-size: revert; font-weight: revert; } .chat-disabled .dx-chat-messagebox { opacity: 0.5; pointer-events: none; } .dx-chat-suggestions .dx-button { max-width: 255px; }
const deployment = 'demo-mini'; const apiVersion = '2024-02-01'; const endpoint = 'https://public-api.devexpress.com/demo-openai'; const apiKey = 'DEMO'; const CHAT_DISABLED_CLASS = 'chat-disabled'; const ALERT_TIMEOUT = 1000 * 60; const user = { id: 'user', }; const assistant = { id: 'assistant', name: 'AI Assistant', }; const suggestionItems = [ { text: '📦 Track my orders', prompt: 'Track my orders' }, { text: '⭐ Check in-stock favorites', prompt: 'Check in-stock favorites' }, { text: '🔄 Start a return', prompt: 'Start a return' }, ]; const SYSTEM_PROMPT = ` You are a logistics support assistant for an online marketplace. The user is logged into their account. If asked about orders, generate realistic and consistent mock data. Use plausible order IDs, dates within the last 30 days, and the following order status values: Processing, Shipped, In Transit, Out for Delivery, Delivered. Never add details outside of given parameters. Do NOT create links. Keep responses structured and professional. When appropriate, use bullet points. The user has exactly 3 recent orders: - #A48291 (In Transit) - #A47903 (Delivered Feb 8) - #A47188 (Processing) Favorite items (example, do NOT use real brand names): VoltEdge 65W Fast Wall Charger (Black) ✅ Back in stock — Ships in 1-2 business days Nimbus Pro Wireless Mouse (Graphite) ❌ Still out of stock — Restock expected Feb 26 PaperLite E-Reader (16 GB, Midnight) ✅ Back in stock — Estimated delivery Feb 20-21 LumaArc Minimal Desk Lamp (Matte Black) ⚠️ Limited stock — Only 3 left WaveTune Over-Ear Wireless Headphones (Ocean Blue) ❌ Out of stock — No restock date available AquaCarry Stainless Steel Bottle (20 oz, Sage) ✅ In stock — Available for same-day pick-up Marketplace Return Policy (Mock) 1. Return Window a. Items can be returned within 30 days of delivery. b. Returns cannot be started before an item is delivered. 2. Condition Requirements a. Items must be unused and in original packaging. b. Opened electronics are eligible if returned within 14 days. c. Digital products are non-refundable. 3. Refund Method a. Refunds are issued to the original payment method. b. Processing time: 3-5 business days after inspection. 4. Shipping Fees a. Returns due to defective or incorrect items: free. b. Returns for change of mind: $4.99 return fee deducted. 5. Exchanges a. Exchanges are available for size or color variants only. b. If replacement is unavailable, refund is issued instead. `;

This demo allows you to configure suggestions as follows:

  • Specify whether the JavaScript Chat displays a predefined prompt in the input field or immediately sends a message with that prompt.
  • Enable single-use suggestions.