DevExtreme v25.2 is now available.

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

Your search did not match any results.

React Tree List - AI Columns

DevExtreme TreeList allows you to add multiple AI columns to the TreeList. These columns auto generate meaningful cell values based on component data and a custom prompt, transforming DevExtreme TreeList into an AI-powered data analysis tool. In this demo, an AI column is fixed to the right side of the component.

Backend API
import React from 'react'; import TreeList, { Column, Scrolling, Paging, AI, } from 'devextreme-react/tree-list'; import type { TreeListTypes } from 'devextreme-react/tree-list'; import { employees } from './data.ts'; import { aiIntegration } from './service.ts'; import type { Employee as EmployeeType } from './types.ts'; import Employee from './Employee.tsx'; import Status from './Status.tsx'; const onAIColumnRequestCreating = ( e: TreeListTypes.AIColumnRequestCreatingEvent<Partial<EmployeeType>> ) => { e.data = e.data.map((item) => ({ ID: item.ID, First_Name: item.First_Name, Last_Name: item.Last_Name, Title: item.Title, })); }; export default function App() { return ( <TreeList id="employees" showBorders={true} dataSource={employees} keyExpr="ID" parentIdExpr="Head_ID" autoExpandAll={true} aiIntegration={aiIntegration} onAIColumnRequestCreating={onAIColumnRequestCreating} className="ai__grid" > <Paging enabled={true} pageSize={10} /> <Scrolling mode="standard" /> <Column caption="Employee" width={260} cellRender={Employee} cssClass="name_cell" /> <Column dataField="Title" caption="Position" width={140} /> <Column dataField="Status" minWidth={180} cellRender={Status} /> <Column dataField="City" width={180} /> <Column dataField="State" width={140} /> <Column dataField="Email" minWidth={200} /> <Column name="AI Column" caption="AI Column" type="ai" width={180} fixed={true} fixedPosition="right" cssClass="ai__cell" > <AI mode="auto" noDataText="No data" prompt="Identify the department where the employee works. Select from the following department list: 'Management', 'Human Resources', 'IT', 'Shipping', 'Support', 'Sales', 'Engineering'. Use 'Engineering' if you cannot find a better match." /> </Column> </TreeList> ); }
import React from 'react'; import TreeList, { Column, Scrolling, Paging, AI, } from 'devextreme-react/tree-list'; import { employees } from './data.js'; import { aiIntegration } from './service.js'; import Employee from './Employee.js'; import Status from './Status.js'; const onAIColumnRequestCreating = (e) => { e.data = e.data.map((item) => ({ ID: item.ID, First_Name: item.First_Name, Last_Name: item.Last_Name, Title: item.Title, })); }; export default function App() { return ( <TreeList id="employees" showBorders={true} dataSource={employees} keyExpr="ID" parentIdExpr="Head_ID" autoExpandAll={true} aiIntegration={aiIntegration} onAIColumnRequestCreating={onAIColumnRequestCreating} className="ai__grid" > <Paging enabled={true} pageSize={10} /> <Scrolling mode="standard" /> <Column caption="Employee" width={260} cellRender={Employee} cssClass="name_cell" /> <Column dataField="Title" caption="Position" width={140} /> <Column dataField="Status" minWidth={180} cellRender={Status} /> <Column dataField="City" width={180} /> <Column dataField="State" width={140} /> <Column dataField="Email" minWidth={200} /> <Column name="AI Column" caption="AI Column" type="ai" width={180} fixed={true} fixedPosition="right" cssClass="ai__cell" > <AI mode="auto" noDataText="No data" prompt="Identify the department where the employee works. Select from the following department list: 'Management', 'Human Resources', 'IT', 'Shipping', 'Support', 'Sales', 'Engineering'. Use 'Engineering' if you cannot find a better match." /> </Column> </TreeList> ); }
import React from 'react'; import { type TreeListTypes } from 'devextreme-react/tree-list'; import { type Employee } from './types'; export default function Employee(props: TreeListTypes.ColumnCellTemplateData<Employee>) { const { First_Name, Last_Name } = props.data; return ( <div className="name__wrapper"> <div className="name__img-wrapper"> <img src={`../../../../images/employees/new/${First_Name} ${Last_Name}.jpg`} alt={`${First_Name} ${Last_Name}`} /> </div> <div className="name__text-wrapper"> <div className="name__text">{First_Name}</div> <div className="name__text">{Last_Name}</div> </div> </div> ); }
import React from 'react'; import { type TreeListTypes } from 'devextreme-react/tree-list'; import { type Employee } from './types'; export default function Status(props: TreeListTypes.ColumnCellTemplateData<Employee>) { const { Status } = props.data; return ( <div className={`status status--${Status.toLowerCase()}`}> <div className="indicator" /> <div>{Status}</div> </div> ); }
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App.tsx'; ReactDOM.render( <App />, document.getElementById('app'), );
import { type Employee } from "./types"; export const employees: Employee[] = [{ ID: 1, Head_ID: 0, First_Name: 'John', Last_Name: 'Heart', Prefix: 'Mr.', Title: 'CEO', City: 'Los Angeles', State: 'California', Email: 'jheart@dx-email.com', Skype: 'jheart_DX_skype', Mobile_Phone: '(213) 555-9392', Birth_Date: '1964-03-16', Hire_Date: '1995-01-15', Status: 'Salaried', }, { ID: 3, Head_ID: 1, First_Name: 'Arthur', Last_Name: 'Miller', Prefix: 'Mr.', Title: 'CTO', City: 'Los Angeles', State: 'California', Email: 'arthurm@dx-email.com', Mobile_Phone: '+1 (310) 555-8583', Birth_Date: '1972-07-11', Hire_Date: '2007-12-18', Status: 'Salaried', }, { ID: 4, Head_ID: 1, First_Name: 'Robert', Last_Name: 'Reagan', Prefix: 'Mr.', Title: 'CMO', City: 'Pasadena', State: 'California', Email: 'robertr@dx-email.com', Mobile_Phone: '+1 (818) 555-2387', Birth_Date: '1974-09-07', Hire_Date: '2002-11-08', Status: 'Salaried', }, { ID: 5, Head_ID: 1, First_Name: 'Greta', Last_Name: 'Sims', Prefix: 'Ms.', Title: 'HR Manager', City: 'Alhambra', State: 'California', Email: 'gretas@dx-email.com', Mobile_Phone: '+1 (818) 555-6546', Birth_Date: '1977-11-22', Hire_Date: '1998-04-23', Status: 'Salaried', }, { ID: 6, Head_ID: 3, First_Name: 'Brett', Last_Name: 'Wade', Prefix: 'Mr.', Title: 'IT Manager', City: 'San Marino', State: 'California', Email: 'brettw@dx-email.com', Mobile_Phone: '+1 (626) 555-0358', Birth_Date: '1968-12-01', Hire_Date: '2009-03-06', Status: 'Salaried', }, { ID: 7, Head_ID: 5, First_Name: 'Sandra', Last_Name: 'Johnson', Prefix: 'Mrs.', Title: 'Controller', City: 'Long Beach', State: 'California', Email: 'sandraj@dx-email.com', Mobile_Phone: '+1 (562) 555-2082', Birth_Date: '1974-11-15', Hire_Date: '2005-05-11', Status: 'Salaried', }, { ID: 21, Head_ID: 6, First_Name: 'Taylor', Last_Name: 'Riley', Prefix: 'Mr.', Title: 'Network Admin', City: 'West Hollywood', State: 'California', Email: 'taylorr@dx-email.com', Mobile_Phone: '+1 (310) 555-7276', Birth_Date: '1982-08-14', Hire_Date: '2012-04-14', Status: 'Salaried', }, { ID: 22, Head_ID: 6, First_Name: 'Amelia', Last_Name: 'Harper', Prefix: 'Mrs.', Title: 'Network Admin', City: 'Los Angeles', State: 'California', Email: 'ameliah@dx-email.com', Mobile_Phone: '+1 (213) 555-4276', Birth_Date: '1983-11-19', Hire_Date: '2011-02-10', Status: 'Salaried', }, { ID: 25, Head_ID: 6, First_Name: 'Karen', Last_Name: 'Goodson', Prefix: 'Miss', Title: 'Programmer', City: 'South Pasadena', State: 'California', Email: 'kareng@dx-email.com', Mobile_Phone: '+1 (626) 555-0908', Birth_Date: '1987-04-26', Hire_Date: '2011-03-14', Status: 'Salaried', }, { ID: 28, Head_ID: 6, First_Name: 'Morgan', Last_Name: 'Kennedy', Prefix: 'Mrs.', Title: 'Graphic Designer', City: 'San Fernando Valley', State: 'California', Email: 'morgank@dx-email.com', Mobile_Phone: '+1 (818) 555-8238', Birth_Date: '1984-07-17', Hire_Date: '2012-01-11', Status: 'Salaried', }, { ID: 29, Head_ID: 28, First_Name: 'Violet', Last_Name: 'Bailey', Prefix: 'Ms.', Title: 'Jr Graphic Designer', City: 'La Canada', State: 'California', Email: 'violetb@dx-email.com', Mobile_Phone: '+1 (818) 555-2478', Birth_Date: '1985-06-10', Hire_Date: '2012-01-19', Status: 'Salaried', }, { ID: 32, Head_ID: 3, First_Name: 'Bart', Last_Name: 'Arnaz', Prefix: 'Mr.', Title: 'Director of Engineering', City: 'Irvine', State: 'California', Email: 'barta@dx-email.com', Mobile_Phone: '+1 (714) 555-2000', Birth_Date: '1979-11-01', Hire_Date: '2008-06-29', Status: 'Salaried', }, { ID: 36, Head_ID: 32, First_Name: 'Samantha', Last_Name: 'Piper', Prefix: 'Ms.', Title: 'Engineer', City: 'Los Angeles', State: 'California', Email: 'samanthap@dx-email.com', Mobile_Phone: '+1 (323) 555-4512', Birth_Date: '1984-12-01', Hire_Date: '2008-01-22', Status: 'Salaried', }, { ID: 38, Head_ID: 32, First_Name: 'Terry', Last_Name: 'Bradley', Prefix: 'Mr.', Title: 'QA Engineer', City: 'Simi Valley', State: 'California', Email: 'terryb@dx-email.com', Mobile_Phone: '+1 (805) 555-2788', Birth_Date: '1984-01-09', Hire_Date: '2007-10-18', Status: 'Salaried', }, { ID: 44, Head_ID: 4, First_Name: 'Clark', Last_Name: 'Morgan', Prefix: 'Mr.', Title: 'Retail Sales Manager', City: 'Martinez', State: 'California', Email: 'clarkm@dx-email.com', Mobile_Phone: '+1 (925) 555-2525', Birth_Date: '1988-04-07', Hire_Date: '2012-04-11', Status: 'Commission', }, { ID: 45, Head_ID: 4, First_Name: 'Todd', Last_Name: 'Hoffman', Prefix: 'Mr.', Title: 'Retail Sales Manager', City: 'Livermore', State: 'California', Email: 'toddh@dx-email.com', Mobile_Phone: '+1 (925) 555-3579', Birth_Date: '1987-03-25', Hire_Date: '2012-04-19', Status: 'Commission', }, { ID: 48, Head_ID: 32, First_Name: 'Brad', Last_Name: 'Farkus', Prefix: 'Mr.', Title: 'Engineer', City: 'Los Angeles', State: 'California', Email: 'bradf@dx-email.com', Mobile_Phone: '+1 (213) 555-3626', Birth_Date: '1991-03-17', Hire_Date: '2010-04-15', Status: 'Terminated', }, { ID: 51, Head_ID: 32, First_Name: 'Stu', Last_Name: 'Pizaro', Prefix: 'Mr.', Title: 'Engineer', City: 'Los Angeles', State: 'California', Email: 'stu@dx-email.com', Mobile_Phone: '+1 (213) 555-2552', Birth_Date: '1985-09-11', Hire_Date: '2011-07-19', Status: 'Terminated', }];
import { AzureOpenAI } from 'openai'; import { AIIntegration } from 'devextreme-react/common/ai-integration'; import type { RequestParams, Response, } from 'devextreme-react/common/ai-integration'; import notify from 'devextreme/ui/notify'; import type { AIMessage } from './types.ts'; const AzureOpenAIConfig = { dangerouslyAllowBrowser: true, deployment: 'gpt-4o-mini', apiVersion: '2024-02-01', endpoint: 'https://public-api.devexpress.com/demo-openai', apiKey: 'DEMO', }; const aiService = new AzureOpenAI(AzureOpenAIConfig); async function getAIResponse(messages: AIMessage[], signal: AbortSignal) { const params = { messages, model: AzureOpenAIConfig.deployment, max_tokens: 1000, temperature: 0.7, }; const response = await aiService.chat.completions.create(params, { signal }); const result = response.choices[0].message?.content; return result; } async function getAIResponseRecursive(messages: AIMessage[], signal: AbortSignal) { return getAIResponse(messages, signal) .catch(async (error) => { if (!error.message.includes('Connection error')) { return Promise.reject(error); } notify({ message: 'Our demo AI service reached a temporary request limit. Retrying in 30 seconds.', width: 'auto', type: 'error', displayTime: 5000, }); await new Promise((resolve) => setTimeout(resolve, 30000)); return getAIResponseRecursive(messages, signal); }); } export const aiIntegration = new AIIntegration({ sendRequest({ prompt }: RequestParams): Response { const isValidRequest = JSON.stringify(prompt.user).length < 5000; if (!isValidRequest) { return { promise: Promise.reject(new Error('Request is too long. Specify a shorter prompt.')), abort: () => {}, }; } const controller = new AbortController(); const signal = controller.signal; const aiPrompt: AIMessage[] = [ { role: 'system', content: prompt.system }, { role: 'user', content: prompt.user }, ]; const promise = getAIResponseRecursive(aiPrompt, signal); const result: Response = { promise, abort: () => { controller.abort(); }, }; return result; }, });
import { OpenAI } from 'openai'; export type AIMessage = (OpenAI.ChatCompletionUserMessageParam | OpenAI.ChatCompletionSystemMessageParam) & { content: string; }; export type Employee = { ID: number; Head_ID: number; First_Name: string; Last_Name: string; Prefix: string; Title: string; City: string; State: string; Email: string; Skype?: string; Mobile_Phone: string; Birth_Date: string; Hire_Date: string; Status: string; };
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://cdn.jsdelivr.net/npm/', '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', 'openai': 'externals:openai.bundle.js', 'devextreme-quill': 'npm:devextreme-quill@1.7.7/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.2.24/dist/dx-diagram.js', 'devexpress-gantt': 'npm:devexpress-gantt@4.1.64/dist/dx-gantt.js', 'inferno': 'npm:inferno@8.2.3/dist/inferno.min.js', 'inferno-compat': 'npm:inferno-compat/dist/inferno-compat.min.js', 'inferno-create-element': 'npm:inferno-create-element@8.2.3/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', '@preact/signals-core': 'npm:@preact/signals-core@1.8.0/dist/signals-core.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-react/common': { main: 'index.js', }, 'devextreme/events/utils': { main: 'index', }, 'devextreme/common/core/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', ], babelOptions: { sourceMaps: false, stage0: true, react: true, }, }; window.process = { env: { NODE_ENV: 'production', }, }; System.config(window.config); // eslint-disable-next-line const useTgzInCSB = ['openai']; let packagesInfo = { "openai": { "version": "4.73.1" } };
import React from 'react'; export default function Employee(props) { const { First_Name, Last_Name } = props.data; return ( <div className="name__wrapper"> <div className="name__img-wrapper"> <img src={`../../../../images/employees/new/${First_Name} ${Last_Name}.jpg`} alt={`${First_Name} ${Last_Name}`} /> </div> <div className="name__text-wrapper"> <div className="name__text">{First_Name}</div> <div className="name__text">{Last_Name}</div> </div> </div> ); }
import { AzureOpenAI } from 'openai'; import { AIIntegration } from 'devextreme-react/common/ai-integration'; import notify from 'devextreme/ui/notify'; const AzureOpenAIConfig = { dangerouslyAllowBrowser: true, deployment: 'gpt-4o-mini', apiVersion: '2024-02-01', endpoint: 'https://public-api.devexpress.com/demo-openai', apiKey: 'DEMO', }; const aiService = new AzureOpenAI(AzureOpenAIConfig); async function getAIResponse(messages, signal) { const params = { messages, model: AzureOpenAIConfig.deployment, max_tokens: 1000, temperature: 0.7, }; const response = await aiService.chat.completions.create(params, { signal }); const result = response.choices[0].message?.content; return result; } async function getAIResponseRecursive(messages, signal) { return getAIResponse(messages, signal).catch(async (error) => { if (!error.message.includes('Connection error')) { return Promise.reject(error); } notify({ message: 'Our demo AI service reached a temporary request limit. Retrying in 30 seconds.', width: 'auto', type: 'error', displayTime: 5000, }); await new Promise((resolve) => setTimeout(resolve, 30000)); return getAIResponseRecursive(messages, signal); }); } export const aiIntegration = new AIIntegration({ sendRequest({ prompt }) { const isValidRequest = JSON.stringify(prompt.user).length < 5000; if (!isValidRequest) { return { promise: Promise.reject(new Error('Request is too long. Specify a shorter prompt.')), abort: () => {}, }; } const controller = new AbortController(); const signal = controller.signal; const aiPrompt = [ { role: 'system', content: prompt.system }, { role: 'user', content: prompt.user }, ]; const promise = getAIResponseRecursive(aiPrompt, signal); const result = { promise, abort: () => { controller.abort(); }, }; return result; }, });
import React from 'react'; export default function Status(props) { const { Status } = props.data; return ( <div className={`status status--${Status.toLowerCase()}`}> <div className="indicator" /> <div>{Status}</div> </div> ); }
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App.js'; ReactDOM.render(<App />, document.getElementById('app'));
export const employees = [ { ID: 1, Head_ID: 0, First_Name: 'John', Last_Name: 'Heart', Prefix: 'Mr.', Title: 'CEO', City: 'Los Angeles', State: 'California', Email: 'jheart@dx-email.com', Skype: 'jheart_DX_skype', Mobile_Phone: '(213) 555-9392', Birth_Date: '1964-03-16', Hire_Date: '1995-01-15', Status: 'Salaried', }, { ID: 3, Head_ID: 1, First_Name: 'Arthur', Last_Name: 'Miller', Prefix: 'Mr.', Title: 'CTO', City: 'Los Angeles', State: 'California', Email: 'arthurm@dx-email.com', Mobile_Phone: '+1 (310) 555-8583', Birth_Date: '1972-07-11', Hire_Date: '2007-12-18', Status: 'Salaried', }, { ID: 4, Head_ID: 1, First_Name: 'Robert', Last_Name: 'Reagan', Prefix: 'Mr.', Title: 'CMO', City: 'Pasadena', State: 'California', Email: 'robertr@dx-email.com', Mobile_Phone: '+1 (818) 555-2387', Birth_Date: '1974-09-07', Hire_Date: '2002-11-08', Status: 'Salaried', }, { ID: 5, Head_ID: 1, First_Name: 'Greta', Last_Name: 'Sims', Prefix: 'Ms.', Title: 'HR Manager', City: 'Alhambra', State: 'California', Email: 'gretas@dx-email.com', Mobile_Phone: '+1 (818) 555-6546', Birth_Date: '1977-11-22', Hire_Date: '1998-04-23', Status: 'Salaried', }, { ID: 6, Head_ID: 3, First_Name: 'Brett', Last_Name: 'Wade', Prefix: 'Mr.', Title: 'IT Manager', City: 'San Marino', State: 'California', Email: 'brettw@dx-email.com', Mobile_Phone: '+1 (626) 555-0358', Birth_Date: '1968-12-01', Hire_Date: '2009-03-06', Status: 'Salaried', }, { ID: 7, Head_ID: 5, First_Name: 'Sandra', Last_Name: 'Johnson', Prefix: 'Mrs.', Title: 'Controller', City: 'Long Beach', State: 'California', Email: 'sandraj@dx-email.com', Mobile_Phone: '+1 (562) 555-2082', Birth_Date: '1974-11-15', Hire_Date: '2005-05-11', Status: 'Salaried', }, { ID: 21, Head_ID: 6, First_Name: 'Taylor', Last_Name: 'Riley', Prefix: 'Mr.', Title: 'Network Admin', City: 'West Hollywood', State: 'California', Email: 'taylorr@dx-email.com', Mobile_Phone: '+1 (310) 555-7276', Birth_Date: '1982-08-14', Hire_Date: '2012-04-14', Status: 'Salaried', }, { ID: 22, Head_ID: 6, First_Name: 'Amelia', Last_Name: 'Harper', Prefix: 'Mrs.', Title: 'Network Admin', City: 'Los Angeles', State: 'California', Email: 'ameliah@dx-email.com', Mobile_Phone: '+1 (213) 555-4276', Birth_Date: '1983-11-19', Hire_Date: '2011-02-10', Status: 'Salaried', }, { ID: 25, Head_ID: 6, First_Name: 'Karen', Last_Name: 'Goodson', Prefix: 'Miss', Title: 'Programmer', City: 'South Pasadena', State: 'California', Email: 'kareng@dx-email.com', Mobile_Phone: '+1 (626) 555-0908', Birth_Date: '1987-04-26', Hire_Date: '2011-03-14', Status: 'Salaried', }, { ID: 28, Head_ID: 6, First_Name: 'Morgan', Last_Name: 'Kennedy', Prefix: 'Mrs.', Title: 'Graphic Designer', City: 'San Fernando Valley', State: 'California', Email: 'morgank@dx-email.com', Mobile_Phone: '+1 (818) 555-8238', Birth_Date: '1984-07-17', Hire_Date: '2012-01-11', Status: 'Salaried', }, { ID: 29, Head_ID: 28, First_Name: 'Violet', Last_Name: 'Bailey', Prefix: 'Ms.', Title: 'Jr Graphic Designer', City: 'La Canada', State: 'California', Email: 'violetb@dx-email.com', Mobile_Phone: '+1 (818) 555-2478', Birth_Date: '1985-06-10', Hire_Date: '2012-01-19', Status: 'Salaried', }, { ID: 32, Head_ID: 3, First_Name: 'Bart', Last_Name: 'Arnaz', Prefix: 'Mr.', Title: 'Director of Engineering', City: 'Irvine', State: 'California', Email: 'barta@dx-email.com', Mobile_Phone: '+1 (714) 555-2000', Birth_Date: '1979-11-01', Hire_Date: '2008-06-29', Status: 'Salaried', }, { ID: 36, Head_ID: 32, First_Name: 'Samantha', Last_Name: 'Piper', Prefix: 'Ms.', Title: 'Engineer', City: 'Los Angeles', State: 'California', Email: 'samanthap@dx-email.com', Mobile_Phone: '+1 (323) 555-4512', Birth_Date: '1984-12-01', Hire_Date: '2008-01-22', Status: 'Salaried', }, { ID: 38, Head_ID: 32, First_Name: 'Terry', Last_Name: 'Bradley', Prefix: 'Mr.', Title: 'QA Engineer', City: 'Simi Valley', State: 'California', Email: 'terryb@dx-email.com', Mobile_Phone: '+1 (805) 555-2788', Birth_Date: '1984-01-09', Hire_Date: '2007-10-18', Status: 'Salaried', }, { ID: 44, Head_ID: 4, First_Name: 'Clark', Last_Name: 'Morgan', Prefix: 'Mr.', Title: 'Retail Sales Manager', City: 'Martinez', State: 'California', Email: 'clarkm@dx-email.com', Mobile_Phone: '+1 (925) 555-2525', Birth_Date: '1988-04-07', Hire_Date: '2012-04-11', Status: 'Commission', }, { ID: 45, Head_ID: 4, First_Name: 'Todd', Last_Name: 'Hoffman', Prefix: 'Mr.', Title: 'Retail Sales Manager', City: 'Livermore', State: 'California', Email: 'toddh@dx-email.com', Mobile_Phone: '+1 (925) 555-3579', Birth_Date: '1987-03-25', Hire_Date: '2012-04-19', Status: 'Commission', }, { ID: 48, Head_ID: 32, First_Name: 'Brad', Last_Name: 'Farkus', Prefix: 'Mr.', Title: 'Engineer', City: 'Los Angeles', State: 'California', Email: 'bradf@dx-email.com', Mobile_Phone: '+1 (213) 555-3626', Birth_Date: '1991-03-17', Hire_Date: '2010-04-15', Status: 'Terminated', }, { ID: 51, Head_ID: 32, First_Name: 'Stu', Last_Name: 'Pizaro', Prefix: 'Mr.', Title: 'Engineer', City: 'Los Angeles', State: 'California', Email: 'stu@dx-email.com', Mobile_Phone: '+1 (213) 555-2552', Birth_Date: '1985-09-11', Hire_Date: '2011-07-19', Status: 'Terminated', }, ];
<!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/25.2.3/css/dx.light.css" /> <link rel="stylesheet" type="text/css" href="styles.css" /> <script src="https://cdn.jsdelivr.net/npm/core-js@2.6.12/client/shim.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/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="tree-list-demo"> <div id="app"></div> </div> </div> </body> </html>
#app .ai__cell { background-color: var(--dx-datagrid-row-alternation-bg); } .ai__grid { min-height: 560px; } #app .name_cell > div { align-items: flex-end; } .name__wrapper { display: flex; align-items: center; gap: 8px; } .name__img-wrapper { width: 40px; height: 40px; border: var(--dx-border-width) solid var(--dx-color-border); border-radius: 50%; cursor: pointer; } .name__img-wrapper img { width: 100%; height: 100%; object-fit: cover; object-position: center; border-radius: 50%; } .name__text-wrapper { width: calc(100% - 48px); } .name__text { margin: 0; padding: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .status { display: flex; align-items: center; } .status--salaried { color: var(--dx-color-success); } .status--commission { color: #f7630c; } .status--terminated { color: var(--dx-color-danger); } .indicator { background-color: currentcolor; margin-right: 8px; border-radius: 50%; height: 12px; width: 12px; }

AI services used for this demo have been rate and data limited. As such, you may experience performance-related delays when exploring the capabilities of TreeList AI Columns.

When connected to your own AI model/service without rate and data limits, TreeList AI Columns will perform seamlessly, without artificial delays. Note that DevExtreme does not offer an AI REST API and does not ship any built-in LLMs/SLMs.

This demo instructs the AI service to identify the department name associated with each employee. You can modify the default prompt or enter a custom prompt in the AI column header menu.

To integrate an AI column into the DevExtreme TreeList, you must:

  • Configure the aiIntegration property at the component or column level (aiIntegration or columns[].ai.aiIntegration).
  • Set the column type to "ai".
  • Specify the column name.
  • Configure columns[].ai options, such as generation mode, predefined prompt, and no data text (displayed when the AI service returns no data for a row).

Our DevExtreme TreeList component uses all visible row data in AI requests, including fields not bound to a column and hidden column fields. This data gives LLMs broader context, but increases the use of AI resources. To limit data included in AI requests, modify the AIColumnRequestCreatingEvent.data parameter in the onAIColumnRequestCreating event handler.