DevExtreme v24.2 is now available.

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

Your search did not match any results.

React Html Editor - Mentions

Our HtmlEditor allows end-users to insert "mentions" and reference others within text or conversation threads as demonstrated in this demo. With this feature, you can introduce functionality that emulates capabilities found in collaboration tools like Microsoft Teams.

Backend API
import React from 'react'; import HtmlEditor from 'devextreme-react/html-editor'; import { employees } from './data.ts'; const mentionsConfig = [{ dataSource: employees, searchExpr: 'text', displayExpr: 'text', valueExpr: 'text', }]; export default function App() { return ( <div> <div id="chat-window"> <div className="message" tabIndex={0}> <div className="photo"> <img alt="Kevin Carter" src="../../../../images/mentions/Kevin-Carter.png" /> </div> <div className="name"> Kevin Carter </div> <div className="date"> 07/03/19 - 12:22AM </div> <div className="text"> <span className="dx-mention" spellCheck="false"><span><span>@</span>John Heart</span></span> What experience do you have in this field? </div> </div> <br /> <div className="message" tabIndex={0}> <div className="photo"> <img alt="John Heart" src="../../../../images/mentions/John-Heart.png" /> </div> <div className="name"> John Heart </div> <div className="date"> 07/03/19 - 12:25AM </div> <div className="text"> I&apos;ve been in the audio/video industry since 2001, and I&apos;ve been the CEO of DevAv since 2009. </div> </div> <br /> <div className="message" tabIndex={0}> <div className="photo"> <img alt="Kevin Carter" src="../../../../images/mentions/Kevin-Carter.png" /> </div> <div className="name"> Kevin Carter </div> <div className="date"> 07/03/19 - 12:26AM </div> <div className="text"> That&apos;s very interesting. <span className="dx-mention" spellCheck="false"><span><span>@</span>Olivia Peyton</span></span>, what do you think? </div> </div> </div> <HtmlEditor mentions={mentionsConfig}> <p> <span className="dx-mention" spellCheck="false" data-marker="@" data-mention-value="Kevin Carter"><span><span>@</span>Kevin Carter</span></span> {" I think John's expertise can be very valuable in our startup."} </p> </HtmlEditor> </div> ); }
import React from 'react'; import HtmlEditor from 'devextreme-react/html-editor'; import { employees } from './data.js'; const mentionsConfig = [ { dataSource: employees, searchExpr: 'text', displayExpr: 'text', valueExpr: 'text', }, ]; export default function App() { return ( <div> <div id="chat-window"> <div className="message" tabIndex={0} > <div className="photo"> <img alt="Kevin Carter" src="../../../../images/mentions/Kevin-Carter.png" /> </div> <div className="name">Kevin Carter</div> <div className="date">07/03/19 - 12:22AM</div> <div className="text"> <span className="dx-mention" spellCheck="false" > <span> <span>@</span>John Heart </span> </span>{' '} What experience do you have in this field? </div> </div> <br /> <div className="message" tabIndex={0} > <div className="photo"> <img alt="John Heart" src="../../../../images/mentions/John-Heart.png" /> </div> <div className="name">John Heart</div> <div className="date">07/03/19 - 12:25AM</div> <div className="text"> I&apos;ve been in the audio/video industry since 2001, and I&apos;ve been the CEO of DevAv since 2009. </div> </div> <br /> <div className="message" tabIndex={0} > <div className="photo"> <img alt="Kevin Carter" src="../../../../images/mentions/Kevin-Carter.png" /> </div> <div className="name">Kevin Carter</div> <div className="date">07/03/19 - 12:26AM</div> <div className="text"> That&apos;s very interesting.{' '} <span className="dx-mention" spellCheck="false" > <span> <span>@</span>Olivia Peyton </span> </span> , what do you think? </div> </div> </div> <HtmlEditor mentions={mentionsConfig}> <p> <span className="dx-mention" spellCheck="false" data-marker="@" data-mention-value="Kevin Carter" > <span> <span>@</span>Kevin Carter </span> </span> {" I think John's expertise can be very valuable in our startup."} </p> </HtmlEditor> </div> ); }
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App.tsx'; ReactDOM.render( <App />, document.getElementById('app'), );
export const employees = [{ text: 'John Heart', team: 'Engineering', icon: '../../../../images/mentions/John-Heart.png', }, { text: 'Kevin Carter', team: 'Engineering', icon: '../../../../images/mentions/Kevin-Carter.png', }, { text: 'Olivia Peyton', team: 'Management', icon: '../../../../images/mentions/Olivia-Peyton.png', }, { text: 'Robert Reagan', team: 'Management', icon: '../../../../images/mentions/Robert-Reagan.png', }, { text: 'Cynthia Stanwick', team: 'Engineering', icon: '../../../../images/mentions/Cynthia-Stanwick.png', }, { text: 'Brett Wade ', team: 'Analysis', icon: '../../../../images/mentions/Brett-Wade.png', }, { text: 'Greta Sims', team: 'QA', icon: '../../../../images/mentions/Greta-Sims.png', }];
window.exports = window.exports || {}; window.config = { transpiler: 'ts', typescriptOptions: { module: 'system', emitDecoratorMetadata: true, experimentalDecorators: true, jsx: 'react', }, meta: { 'react': { 'esModule': true, }, 'typescript': { 'exports': 'ts', }, 'devextreme/time_zone_utils.js': { 'esModule': true, }, 'devextreme/localization.js': { 'esModule': true, }, 'devextreme/viz/palette.js': { 'esModule': true, }, 'openai': { 'esModule': true, }, }, paths: { 'npm:': 'https://unpkg.com/', 'bundles:': '../../../../bundles/', 'externals:': '../../../../bundles/externals/', }, defaultExtension: 'js', map: { 'ts': 'npm:plugin-typescript@8.0.0/lib/plugin.js', 'typescript': 'npm:typescript@4.2.4/lib/typescript.js', 'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js', 'react': 'npm:react@17.0.2/umd/react.development.js', 'react-dom': 'npm:react-dom@17.0.2/umd/react-dom.development.js', 'prop-types': 'npm:prop-types/prop-types.js', 'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js', 'luxon': 'npm:luxon@3.4.4/build/global/luxon.min.js', 'es6-object-assign': 'npm:es6-object-assign', 'devextreme': 'npm:devextreme@link:../../packages/devextreme/artifacts/npm/devextreme/cjs', 'devextreme-react': 'npm:devextreme-react@link:../../packages/devextreme-react/npm/cjs', 'devextreme-quill': 'npm:devextreme-quill@1.7.1/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.2.5/dist/dx-diagram.js', 'devexpress-gantt': 'npm:devexpress-gantt@4.1.54/dist/dx-gantt.js', '@devextreme/runtime': 'npm:@devextreme/runtime@3.0.12', 'inferno': 'npm:inferno@7.4.11/dist/inferno.min.js', 'inferno-compat': 'npm:inferno-compat/dist/inferno-compat.min.js', 'inferno-create-element': 'npm:inferno-create-element@7.4.11/dist/inferno-create-element.min.js', 'inferno-dom': 'npm:inferno-dom/dist/inferno-dom.min.js', 'inferno-hydrate': 'npm:inferno-hydrate/dist/inferno-hydrate.min.js', 'inferno-clone-vnode': 'npm:inferno-clone-vnode/dist/inferno-clone-vnode.min.js', 'inferno-create-class': 'npm:inferno-create-class/dist/inferno-create-class.min.js', 'inferno-extras': 'npm:inferno-extras/dist/inferno-extras.min.js', 'devextreme-cldr-data': 'npm:devextreme-cldr-data@1.0.3', // SystemJS plugins 'plugin-babel': 'npm:systemjs-plugin-babel@0.0.25/plugin-babel.js', 'systemjs-babel-build': 'npm:systemjs-plugin-babel@0.0.25/systemjs-babel-browser.js', // Prettier 'prettier/standalone': 'npm:prettier@2.8.8/standalone.js', 'prettier/parser-html': 'npm:prettier@2.8.8/parser-html.js', }, packages: { 'devextreme': { defaultExtension: 'js', }, 'devextreme-react': { main: 'index.js', }, 'devextreme/events/utils': { main: 'index', }, 'devextreme/localization/messages': { format: 'json', defaultExtension: 'json', }, 'devextreme/events': { main: 'index', }, 'es6-object-assign': { main: './index.js', defaultExtension: 'js', }, }, packageConfigPaths: [ 'npm:@devextreme/*/package.json', 'npm:@devextreme/runtime@3.0.12/inferno/package.json', ], babelOptions: { sourceMaps: false, stage0: true, react: true, }, }; System.config(window.config);
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App.js'; ReactDOM.render(<App />, document.getElementById('app'));
export const employees = [ { text: 'John Heart', team: 'Engineering', icon: '../../../../images/mentions/John-Heart.png', }, { text: 'Kevin Carter', team: 'Engineering', icon: '../../../../images/mentions/Kevin-Carter.png', }, { text: 'Olivia Peyton', team: 'Management', icon: '../../../../images/mentions/Olivia-Peyton.png', }, { text: 'Robert Reagan', team: 'Management', icon: '../../../../images/mentions/Robert-Reagan.png', }, { text: 'Cynthia Stanwick', team: 'Engineering', icon: '../../../../images/mentions/Cynthia-Stanwick.png', }, { text: 'Brett Wade ', team: 'Analysis', icon: '../../../../images/mentions/Brett-Wade.png', }, { text: 'Greta Sims', team: 'QA', icon: '../../../../images/mentions/Greta-Sims.png', }, ];
<!DOCTYPE html> <html 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" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/24.2.3/css/dx.light.css" /> <link rel="stylesheet" type="text/css" href="styles.css" /> <script src="https://unpkg.com/core-js@2.6.12/client/shim.min.js"></script> <script src="https://unpkg.com/systemjs@0.21.3/dist/system.js"></script> <script type="text/javascript" src="config.js"></script> <script type="text/javascript"> System.import("./index.tsx"); </script> </head> <body class="dx-viewport"> <div class="demo-container"> <div id="app"></div> </div> </body> </html>
#chat-window { background-color: rgba(191, 191, 191, 0.15); height: 350px; padding: 10px; } .dx-htmleditor { height: 100px; } #send { float: right; margin: 10px 0; } .message { height: 85px; background-color: var(--dx-component-color-bg); display: inline-block; max-width: 60%; border-radius: 5px; margin: 5px; padding: 10px; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); } .name { font-weight: bold; } .date { opacity: 0.5; } .photo { float: left; height: 100%; } .photo > img { width: 40px; height: 40px; display: block; border-radius: 40px; margin-right: 10px; }

A "mention" is triggered by a marker. You are free to choose a "marker" of your choice (this demo uses the @ symbol to trigger a "mention"). User names are stored as items in a dataSource. Data can be retrieved from multiple data sources. When using multiple data sources, you must assign an unique marker to each.

To "mention" a user, simply enter the @ symbol and select the desired record from the "Mentions" drop-down user list. Like today's most popular collaboration tools, you can enter additional characters to filter the records displayed within the "Mentions" drop-down user list.