DevExtreme v23.2 is now available.

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

Your search did not match any results.

Tables

DevExtreme HTML/Markdown Editor allows users to create and manage tables. This demo illustrates table resize support and table management with the toolbar, context menu, and in code.

Manage Tables with the Built-in Toolbar

To manage tables via a built-in toolbar, add the following items to it:

  • "insertTable" / "deleteTable"
    Manage a table.

  • "insertRowAbove" / "insertRowBelow" / "deleteRow"
    Manage rows.

  • "insertColumnLeft" / "insertColumnRight" / "deleteColumn"
    Manage columns.

  • "tableProperties" / "cellProperties"
    Open a pop-up window with table or cell customization options.

Manage Tables with the Context Menu

To manage table layouts with the context menu, set the tableContextMenu.enabled property to true. In this demo, you can click the Enable Table Context Menu check box under the HtmlEditor to enable or disable this property. When it is enabled, right-click a table cell to open the context menu.

NOTE

The context menu cannot be used to create new tables. The menu is only available within table boundaries. If you want users to create tables, add an "insertTable" item to the toolbar.

If you need to customize menu commands, override the tableContextMenu.items array. Refer to its description for a code example.

Manage Tables Programmatically

You can perform table-related actions in code. Use the getModule method to access the Table module. This module contains methods with names that match toolbar item names listed above. Refer to the following topic for the complete method list and code examples: DevExtreme Quill modules: Table.

Resize Tables

If you want to resize table rows and columns, set the tableResizing.enabled property to true. In this demo, you can use the Allow Table Resizing check box to change the property value.

You can also set the tableResizing.minColumnWidth and tableResizing.minRowHeight properties to specify minimum column width and row height. If you do not set these properties, width and height are determined by cell content. This demo illustrates the latter behavior (when you reduce column width or row height to small values).

Backend API
import React, { useCallback, useState } from 'react'; import HtmlEditor, { TableContextMenu, TableResizing, Toolbar, Item, } from 'devextreme-react/html-editor'; import { CheckBox, CheckBoxTypes } from 'devextreme-react/check-box'; import { markup } from './data.ts'; export default function App() { const [allowResizing, setAllowResizing] = useState(true); const [contextMenuEnabled, setContextMenuEnabled] = useState(true); const tableResizingChanged = useCallback((e: CheckBoxTypes.ValueChangedEvent) => { setAllowResizing(e.value); }, [setAllowResizing]); const tableContextMenuChanged = useCallback((e: CheckBoxTypes.ValueChangedEvent) => { setContextMenuEnabled(e.value); }, [setContextMenuEnabled]); return ( <div className="widget-container"> <HtmlEditor height="750px" defaultValue={markup}> <TableContextMenu enabled={contextMenuEnabled} /> <TableResizing enabled={allowResizing} /> <Toolbar> <Item name="bold" /> <Item name="color" /> <Item name="separator" /> <Item name="alignLeft" /> <Item name="alignCenter" /> <Item name="alignRight" /> <Item name="separator" /> <Item name="insertTable" /> <Item name="insertHeaderRow" /> <Item name="insertRowAbove" /> <Item name="insertRowBelow" /> <Item name="separator" /> <Item name="insertColumnLeft" /> <Item name="insertColumnRight" /> <Item name="separator" /> <Item name="deleteColumn" /> <Item name="deleteRow" /> <Item name="deleteTable" /> <Item name="separator" /> <Item name="cellProperties" /> <Item name="tableProperties" /> </Toolbar> </HtmlEditor> <div className="options"> <div className="caption">Options</div> <div className="option"> <CheckBox text="Allow Table Resizing" value={allowResizing} onValueChanged={tableResizingChanged} /> </div> <div className="option"> <CheckBox text="Enable Table Context Menu" value={contextMenuEnabled} onValueChanged={tableContextMenuChanged} /> </div> </div> </div> ); }
import React, { useCallback, useState } from 'react'; import HtmlEditor, { TableContextMenu, TableResizing, Toolbar, Item, } from 'devextreme-react/html-editor'; import { CheckBox } from 'devextreme-react/check-box'; import { markup } from './data.js'; export default function App() { const [allowResizing, setAllowResizing] = useState(true); const [contextMenuEnabled, setContextMenuEnabled] = useState(true); const tableResizingChanged = useCallback( (e) => { setAllowResizing(e.value); }, [setAllowResizing], ); const tableContextMenuChanged = useCallback( (e) => { setContextMenuEnabled(e.value); }, [setContextMenuEnabled], ); return ( <div className="widget-container"> <HtmlEditor height="750px" defaultValue={markup} > <TableContextMenu enabled={contextMenuEnabled} /> <TableResizing enabled={allowResizing} /> <Toolbar> <Item name="bold" /> <Item name="color" /> <Item name="separator" /> <Item name="alignLeft" /> <Item name="alignCenter" /> <Item name="alignRight" /> <Item name="separator" /> <Item name="insertTable" /> <Item name="insertHeaderRow" /> <Item name="insertRowAbove" /> <Item name="insertRowBelow" /> <Item name="separator" /> <Item name="insertColumnLeft" /> <Item name="insertColumnRight" /> <Item name="separator" /> <Item name="deleteColumn" /> <Item name="deleteRow" /> <Item name="deleteTable" /> <Item name="separator" /> <Item name="cellProperties" /> <Item name="tableProperties" /> </Toolbar> </HtmlEditor> <div className="options"> <div className="caption">Options</div> <div className="option"> <CheckBox text="Allow Table Resizing" value={allowResizing} onValueChanged={tableResizingChanged} /> </div> <div className="option"> <CheckBox text="Enable Table Context Menu" value={contextMenuEnabled} onValueChanged={tableContextMenuChanged} /> </div> </div> </div> ); }
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App.tsx'; ReactDOM.render( <App />, document.getElementById('app'), );
export const markup = ` <h2> Hardware Upgrade </h2> <br> <table> <thead> <tr> <th style="text-align: left; width: 320px;">Task Subject</th> <th style="text-align: center;">Status</th> <th style="text-align: right;">Progress</th> </tr> </thead> <tbody> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Approve Personal Computer Upgrade Plan</td> <td style="text-align: center; color: #5cb85c;"> <p style="font-size: 1.15em;">✓</p> <p>Completed</p> </td> <td style="text-align: right;">100%</td> </tr> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Prepare workspaces</td> <td style="text-align: center; color: #5cb85c;"> <p style="font-size: 1.15em;">✓</p> <p>Completed</p> </td> <td style="text-align: right;">100%</td> </tr> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Upgrade Server Hardware</td> <td style="text-align: center;"> <p style="font-size: 1.15em;">⟳</p> <p>In Progress</p> </td> <td style="text-align: right;">45%</td> </tr> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Upgrade Personal Computers</td> <td style="text-align: center; color: #f0ad4e;"> <p style="font-size: 1.15em;">‖</p> <p>Need Assistance</p> </td> <td style="text-align: right;">80%</td> </tr> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Replace HDD with SSD</td> <td style="text-align: center;"> <p style="font-size: 1.15em;">⟳</p> <p>In Progress</p> </td> <td style="text-align: right;">80%</td> </tr> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Purchase a New Server</td> <td style="text-align: center; color: #d9534f;"> <p style="font-size: 1.15em;">✖</p> <p>Canceled</p> </td> <td style="text-align: right;">15%</td> </tr> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Purchase Laptops</td> <td style="text-align: center; color: #5cb85c;"> <p style="font-size: 1.15em;">✓</p> <p>Completed</p> </td> <td style="text-align: right;">100%</td> </tr> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Prepare a list of necessary devices for testing</td> <td style="text-align: center; color: #5cb85c;"> <p style="font-size: 1.15em;">✓</p> <p>Completed</p> </td> <td style="text-align: right;">100%</td> </tr> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Purchase devices for testing</td> <td style="text-align: center; color: #f0ad4e;"> <p style="font-size: 1.15em;">‖</p> <p>Need Assistance</p> </td> <td style="text-align: right;">25%</td> </tr> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Recycle Broken Hardware</td> <td style="text-align: center; color: #5cb85c;"> <p style="font-size: 1.15em;">✓</p> <p>Completed</p> </td> <td style="text-align: right;">100%</td> </tr> </tbody> </table> <br> `;
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, }, }, paths: { 'npm:': 'https://unpkg.com/', }, defaultExtension: 'js', map: { 'ts': 'npm:plugin-typescript@4.2.4/lib/plugin.js', 'typescript': 'npm:typescript@4.2.4/lib/typescript.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@15.8.1/prop-types.js', 'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js', 'luxon': 'npm:luxon@1.28.1/build/global/luxon.min.js', 'es6-object-assign': 'npm:es6-object-assign@1.1.0', 'devextreme': 'npm:devextreme@23.2.5/cjs', 'devextreme-react': 'npm:devextreme-react@23.2.5/cjs', 'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js', 'devextreme-quill': 'npm:devextreme-quill@1.6.4/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.2.5/dist/dx-diagram.js', 'devexpress-gantt': 'npm:devexpress-gantt@4.1.51/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@7.4.11/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.4/standalone.js', 'prettier/parser-html': 'npm:prettier@2.8.4/parser-html.js', }, packages: { 'devextreme': { defaultExtension: 'js', }, 'devextreme-react': { main: 'index.js', }, 'devextreme/events/utils': { main: 'index', }, 'devextreme/localization/messages': { format: 'json', defaultExtension: '', }, '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 markup = ` <h2> Hardware Upgrade </h2> <br> <table> <thead> <tr> <th style="text-align: left; width: 320px;">Task Subject</th> <th style="text-align: center;">Status</th> <th style="text-align: right;">Progress</th> </tr> </thead> <tbody> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Approve Personal Computer Upgrade Plan</td> <td style="text-align: center; color: #5cb85c;"> <p style="font-size: 1.15em;">✓</p> <p>Completed</p> </td> <td style="text-align: right;">100%</td> </tr> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Prepare workspaces</td> <td style="text-align: center; color: #5cb85c;"> <p style="font-size: 1.15em;">✓</p> <p>Completed</p> </td> <td style="text-align: right;">100%</td> </tr> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Upgrade Server Hardware</td> <td style="text-align: center;"> <p style="font-size: 1.15em;">⟳</p> <p>In Progress</p> </td> <td style="text-align: right;">45%</td> </tr> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Upgrade Personal Computers</td> <td style="text-align: center; color: #f0ad4e;"> <p style="font-size: 1.15em;">‖</p> <p>Need Assistance</p> </td> <td style="text-align: right;">80%</td> </tr> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Replace HDD with SSD</td> <td style="text-align: center;"> <p style="font-size: 1.15em;">⟳</p> <p>In Progress</p> </td> <td style="text-align: right;">80%</td> </tr> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Purchase a New Server</td> <td style="text-align: center; color: #d9534f;"> <p style="font-size: 1.15em;">✖</p> <p>Canceled</p> </td> <td style="text-align: right;">15%</td> </tr> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Purchase Laptops</td> <td style="text-align: center; color: #5cb85c;"> <p style="font-size: 1.15em;">✓</p> <p>Completed</p> </td> <td style="text-align: right;">100%</td> </tr> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Prepare a list of necessary devices for testing</td> <td style="text-align: center; color: #5cb85c;"> <p style="font-size: 1.15em;">✓</p> <p>Completed</p> </td> <td style="text-align: right;">100%</td> </tr> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Purchase devices for testing</td> <td style="text-align: center; color: #f0ad4e;"> <p style="font-size: 1.15em;">‖</p> <p>Need Assistance</p> </td> <td style="text-align: right;">25%</td> </tr> <tr style="text-align: center;"> <td style="text-align: left; width: 320px;">Recycle Broken Hardware</td> <td style="text-align: center; color: #5cb85c;"> <p style="font-size: 1.15em;">✓</p> <p>Completed</p> </td> <td style="text-align: right;">100%</td> </tr> </tbody> </table> <br> `;
<!DOCTYPE html> <html> <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=1.0" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/23.2.5/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>
.demo-container { height: 950px; } .options { padding: 20px; background-color: rgba(191, 191, 191, 0.15); margin-top: 20px; } .caption { font-size: 18px; font-weight: 500; } .option { margin-top: 10px; }