DevExtreme v23.2 is now available.

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

Your search did not match any results.

Adaptability

This demo demonstrates how the DevExtreme Toolbar component can adapt itself to different screen widths.

If you would like to learn more about our feature-complete Toolbar component, please refer to the following tutorial: Getting Started with Toolbar.

In this demo, you can drag our Toolbar container's resizing handle to visualize resize operations and view our rendering implementation on different screens. When used in single-line mode (default), our Toolbar does not wrap content and displays an overflow menu for items that do not fit within the container. Use the locateInMenu property to control whether items appear in the overflow menu.

If Toolbar width exceeds container width (and if you enable the component’s multiline property), our Toolbar wraps content across multiple lines.

Backend API
<template> <div> <div class="widget-container"> <DxResizable class="resizable-container" area=".widget-container" handles="right" :min-width="500" :min-height="150" :max-height="370" > <DxToolbar :multiline="multiline"> <DxItem location="before" widget="dxButton" > <DxButton icon="undo" :on-click="onUndoButtonClick" /> </DxItem> <DxItem location="before" widget="dxButton" > <DxButton icon="redo" :on-click="onRedoButtonClick" /> </DxItem> <DxItem location="before" locate-in-menu="auto" template="separatorTemplate" menu-item-template="menuSeparatorTemplate" /> <DxItem location="before" locate-in-menu="auto" > <DxDropDownButton width="100%" display-expr="text" key-expr="size" item-template="fontSizeTemplate" :use-select-mode="true" :items="fontSizes" :selected-item-key="fontSize" :on-selection-changed="onFontSizeSelectionChanged" > <template #fontSizeTemplate="{ data }"> <div :style="{ fontSize: data.size + 'px' }"> {{ data.text }} </div> </template> </DxDropDownButton> </DxItem> <DxItem location="before" locate-in-menu="auto" > <DxDropDownButton width="100%" icon="indent" display-expr="text" key-expr="lineHeight" :use-select-mode="true" :items="lineHeights" :selected-item-key="lineHeight" :on-selection-changed="onLineHeightSelectionChanged" /> </DxItem> <DxItem location="before" locate-in-menu="auto" > <DxSelectBox placeholder="Font" display-expr="text" :input-attr="{ 'aria-label': 'Font' }" :data-source="fontFamilies" :on-item-click="onFontFamilyClick" /> </DxItem> <DxItem location="before" locate-in-menu="auto" template="separatorTemplate" menu-item-template="menuSeparatorTemplate" /> <DxItem location="before"> <DxButtonGroup display-expr="text" key-expr="icon" styling-mode="outlined" selection-mode="multiple" :items="fontStyles" :on-item-click="onFontStyleItemClick" /> </DxItem> <DxItem location="before" template="separatorTemplate" /> <DxItem location="before" locate-in-menu="auto" template="textAlignTemplate" menu-item-template="textAlignMenuTemplate" widget="dxButtonGroup" /> <DxItem location="before"> <DxButtonGroup key-expr="alignment" styling-mode="outlined" :items="listTypes" :on-item-click="onListTypeButtonClick" /> </DxItem> <DxItem location="before" locate-in-menu="auto" template="separatorTemplate" menu-item-template="menuSeparatorTemplate" /> <DxItem location="before" locate-in-menu="auto" > <DxSelectBox display-expr="text" value-expr="text" :input-attr="{ 'aria-label': 'Text Style' }" :data-source="headings" :value="heading" :on-item-click="onHeadingClick" /> </DxItem> <DxItem location="before" locate-in-menu="auto" template="separatorTemplate" menu-item-template="menuSeparatorTemplate" /> <DxItem location="before" locate-in-menu="auto" show-text="inMenu" widget="dxButton" > <DxButton icon="link" text="Link" :on-click="onLinkButtonClick" /> </DxItem> <DxItem location="before" locate-in-menu="auto" show-text="inMenu" widget="dxButton" > <DxButton icon="image" text="Add image" :on-click="onAddImageButtonClick" /> </DxItem> <DxItem location="before" locate-in-menu="auto" template="separatorTemplate" menu-item-template="menuSeparatorTemplate" /> <DxItem location="before" locate-in-menu="auto" show-text="inMenu" widget="dxButton" > <DxButton icon="clearformat" text="Clear formating" :on-click="onClearButtonClick" /> </DxItem> <DxItem location="before" locate-in-menu="auto" show-text="inMenu" widget="dxButton" > <DxButton icon="codeblock" text="Code block" :on-click="onCodeBlockButtonClick" /> </DxItem> <DxItem location="before" locate-in-menu="auto" show-text="inMenu" widget="dxButton" > <DxButton icon="blockquote" text="Blockquote" :on-click="onQuoteButtonClick" /> </DxItem> <DxItem location="before" locate-in-menu="auto" template="separatorTemplate" menu-item-template="menuSeparatorTemplate" /> <DxItem location="after" widget="dxButton" show-text="inMenu" > <DxButton icon="attach" text="Attach" :on-click="onAttachButtonClick" /> </DxItem> <DxItem locate-in-menu="always" widget="dxButton" show-text="inMenu" > <DxButton icon="help" text="About" :on-click="onAboutButtonClick" /> </DxItem> <template #separatorTemplate> <div class="toolbar-separator"/> </template> <template #menuSeparatorTemplate> <div class="toolbar-menu-separator"/> </template> <template #textAlignTemplate> <DxButtonGroup key-expr="alignment" styling-mode="outlined" :items="textAlignItems" :selected-item-keys="textAlign" @item-click="onTextAlignItemClick" /> </template> <template #textAlignMenuTemplate> <DxButtonGroup :items="textAlignItemsExtended" display-expr="text" :selected-item-keys="textAlign" key-expr="alignment" styling-mode="outlined" @item-click="onTextAlignItemClick" /> </template> </DxToolbar> </DxResizable> </div> <div class="options-container"> <div class="caption">Options</div> <DxCheckBox v-model="multiline" text="Multiline mode" /> </div> </div> </template> <script setup lang="ts"> import { ref } from 'vue'; import DxCheckBox from 'devextreme-vue/check-box'; import DxToolbar, { DxItem } from 'devextreme-vue/toolbar'; import DxButton from 'devextreme-vue/button'; import DxButtonGroup from 'devextreme-vue/button-group'; import DxResizable from 'devextreme-vue/resizable'; import DxDropDownButton from 'devextreme-vue/drop-down-button'; import DxSelectBox from 'devextreme-vue/select-box'; import notify from 'devextreme/ui/notify'; import { fontSizes, lineHeights, fontFamilies, fontStyles, headings, textAlignItems, textAlignItemsExtended, listTypes, } from './data.ts'; import 'devextreme/ui/select_box'; const lineHeightDefault = lineHeights[1].lineHeight; const textAlignDefault = [textAlignItems[0].alignment]; const fontSizeDefault = fontSizes[2].size; const headingDefault = headings[0].text; const multiline = ref(true); const lineHeight = ref(lineHeightDefault); const textAlign = ref(textAlignDefault); const fontSize = ref(fontSizeDefault); const heading = ref(headingDefault); function onTextAlignItemClick(e) { const { alignment, hint } = e.itemData; textAlign.value = alignment; onButtonClick(hint); } function onButtonClick(name) { notify(`The "${name}" button has been clicked`); } function onUndoButtonClick() { onButtonClick('Undo'); } function onRedoButtonClick() { onButtonClick('Redo'); } function onFontStyleItemClick(e) { onButtonClick(e.itemData.hint); } function onListTypeButtonClick(e) { onButtonClick(e.itemData.hint); } function onLinkButtonClick() { onButtonClick('Link'); } function onAddImageButtonClick() { onButtonClick('Add Image'); } function onClearButtonClick() { onButtonClick('Clear Formating'); } function onCodeBlockButtonClick() { onButtonClick('Code Block'); } function onQuoteButtonClick() { onButtonClick('Blockquote'); } function onAttachButtonClick() { onButtonClick('Attach'); } function onAboutButtonClick() { onButtonClick('About'); } function onSelectionChanged(name) { notify(`The "${name}" value has been changed`); } function onFontSizeSelectionChanged() { onSelectionChanged('Font Size'); } function onLineHeightSelectionChanged() { onSelectionChanged('Line Height'); } function onHeadingClick() { notify('The "Heading" value has been changed'); } function onFontFamilyClick() { notify('The "Font Family" value has been changed'); } </script> <style> .dx-resizable-handle::after { content: ""; position: absolute; width: 9px; height: 36px; border: none; border-radius: 50px; background-color: #fff; box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.24); } .dx-resizable-handle-right::after { top: 50%; right: -5px; transform: translateY(-50%); } .dx-toolbar.dx-toolbar-multiline .dx-toolbar-item { margin-bottom: 5px; } .widget-container { margin-right: 10px; } .resizable-container { padding: 10px; height: 300px; border: 1px dotted #999; border-radius: 4px; box-sizing: border-box; } .options-container { margin-top: 20px; padding: 20px; background-color: rgba(191, 191, 191, 0.15); position: relative; } .caption { font-size: 18px; font-weight: 500; margin-bottom: 10px; } .toolbar-separator { height: 36px; margin: 0 5px; border-left: 1px solid #ddd; } .toolbar-menu-separator { height: 1px; border-bottom: 1px solid #ddd; } </style>
window.exports = window.exports || {}; window.config = { transpiler: 'plugin-babel', meta: { '*.vue': { loader: 'vue-loader', }, '*.ts': { loader: 'demo-ts-loader', }, '*.svg': { loader: 'svg-loader', }, 'devextreme/time_zone_utils.js': { 'esModule': true, }, 'devextreme/localization.js': { 'esModule': true, }, 'devextreme/viz/palette.js': { 'esModule': true, }, }, paths: { 'root:': '../../../../../', 'npm:': 'https://unpkg.com/', }, map: { 'vue': 'npm:vue@3.3.4/dist/vue.esm-browser.js', 'vue-loader': 'npm:dx-systemjs-vue-browser@1.1.1/index.js', 'demo-ts-loader': 'root:utils/demo-ts-loader.js', 'svg-loader': 'root:utils/svg-loader.js', 'mitt': 'npm:mitt/dist/mitt.umd.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-vue': 'npm:devextreme-vue@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', '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-vue': { main: 'index.js', }, 'devextreme': { defaultExtension: 'js', }, 'devextreme/events/utils': { main: 'index', }, '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, }, }; System.config(window.config);
export const fontSizes = [ { size: 10, text: '10px' }, { size: 12, text: '12px' }, { size: 14, text: '14px' }, { size: 16, text: '16px' }, { size: 18, text: '18px' }, ]; export const lineHeights = [ { lineHeight: 1, text: '1' }, { lineHeight: 1.35, text: '1.35' }, { lineHeight: 1.5, text: '1.5' }, { lineHeight: 2, text: '2' }, ]; export const fontFamilies = [ { text: 'Arial' }, { text: 'Courier New' }, { text: 'Georgia' }, { text: 'Impact' }, { text: 'Lucida Console' }, { text: 'Tahoma' }, { text: 'Times New Roman' }, ]; export const headings = [ { text: 'Normal text' }, { text: 'Heading 1' }, { text: 'Heading 2' }, { text: 'Heading 3' }, { text: 'Heading 4' }, { text: 'Heading 5' }, ]; export const fontStyles = [ { icon: 'bold', hint: 'Bold', }, { icon: 'italic', hint: 'Italic', }, { icon: 'underline', hint: 'Underlined', }, { icon: 'strike', hint: 'Strikethrough', }, ]; export const textAlignItemsExtended = [ { icon: 'alignleft', alignment: 'left', hint: 'Align Left', text: 'Align left', }, { icon: 'aligncenter', alignment: 'center', hint: 'Center', text: 'Center', }, { icon: 'alignright', alignment: 'right', hint: 'Align Right', text: 'Align right', }, { icon: 'alignjustify', alignment: 'justify', hint: 'Justify', text: 'Justify', }, ]; export const textAlignItems = textAlignItemsExtended.map((item) => { const { icon, alignment, hint } = item; return { icon, alignment, hint, }; }); export const listTypes = [ { icon: 'orderedlist', alignment: 'orderedlist', hint: 'Ordered', }, { icon: 'bulletlist', alignment: 'bulletlist', hint: 'Bullet', }, ];
import { createApp } from 'vue'; import App from './App.vue'; createApp(App).mount('#app');
<!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" /> <script src="https://unpkg.com/typescript@4.2.4/lib/typescript.js"></script> <script type="module"> import * as vueCompilerSFC from "https://unpkg.com/@vue/compiler-sfc@3.3.4/dist/compiler-sfc.esm-browser.js"; window.vueCompilerSFC = vueCompilerSFC; </script> <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.ts"); </script> </head> <body class="dx-viewport"> <div class="demo-container"> <div id="app"> </div> </div> </body> </html>