DevExtreme v24.1 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.

Backend API
<div class="widget-container"> <dx-resizable class="resizable-container" [minWidth]="500" [minHeight]="150" [maxHeight]="370" handles="right" area=".widget-container" > <dx-toolbar #toolbar [multiline]="true"> <dxi-item location="before" widget="dxButton"> <div *dxTemplate> <dx-button icon="undo" [stylingMode]="stylingMode" (onClick)="onButtonClick('Undo')" ></dx-button> </div> </dxi-item> <dxi-item location="before" widget="dxButton"> <div *dxTemplate> <dx-button icon="redo" [stylingMode]="stylingMode" (onClick)="onButtonClick('Redo')" ></dx-button> </div> </dxi-item> <dxi-item location="before" locateInMenu="auto" menuItemTemplate="menuSeparatorTemplate" > <div *dxTemplate> <div class="toolbar-separator"></div> </div> </dxi-item> <dxi-item location="before" locateInMenu="auto" widget="dxDropDownButton"> <div *dxTemplate> <dx-drop-down-button width="100%" displayExpr="text" keyExpr="size" itemTemplate="fontSizeTemplate" [stylingMode]="stylingMode" [items]="fontSizes" [selectedItemKey]="fontSizes[2].size" [useSelectMode]="true" (onSelectionChanged)="onSelectionChanged('Font Size')" > <div *dxTemplate="let data of 'fontSizeTemplate'"> <div [style.fontSize]="data.size + 'px'">{{ data.text }}</div> </div> </dx-drop-down-button> </div> </dxi-item> <dxi-item location="before" locateInMenu="auto" widget="dxDropDownButton"> <div *dxTemplate> <dx-drop-down-button width="100%" icon="indent" displayExpr="text" keyExpr="lineHeight" [stylingMode]="stylingMode" [items]="lineHeights" [useSelectMode]="true" [selectedItemKey]="lineHeight" (onSelectionChanged)="onSelectionChanged('Line Height')" ></dx-drop-down-button> </div> </dxi-item> <dxi-item location="before" locateInMenu="auto" widget="dxSelectBox"> <div *dxTemplate> <dx-select-box placeholder="Font" displayExpr="text" [inputAttr]="{ 'aria-label': 'Font' }" [items]="fontFamilies" (onItemClick)="onFontFamilyClick()" ></dx-select-box> </div> </dxi-item> <dxi-item location="before" locateInMenu="auto" menuItemTemplate="menuSeparatorTemplate" > <div *dxTemplate> <div class="toolbar-separator"></div> </div> </dxi-item> <dxi-item location="before" widget="dxButtonGroup"> <div *dxTemplate> <dx-button-group displayExpr="text" keyExpr="icon" stylingMode="outlined" selectionMode="multiple" [items]="fontStyles" (onItemClick)="onButtonClick($event.itemData.hint)" ></dx-button-group> </div> </dxi-item> <dxi-item location="before"> <div *dxTemplate> <div class="toolbar-separator"></div> </div> </dxi-item> <dxi-item widget="dxButtonGroup" location="before" locateInMenu="auto" menuItemTemplate="menuTextAlignTemplate" > <div *dxTemplate> <dx-button-group keyExpr="alignment" stylingMode="outlined" [items]="textAlignItems" [(selectedItemKeys)]="selectedTextAlign" (onItemClick)="onTextAlignChanged($event)" ></dx-button-group> </div> </dxi-item> <dxi-item location="before" widget="dxButtonGroup"> <div *dxTemplate> <dx-button-group keyExpr="alignment" stylingMode="outlined" [items]="listTypes" (onItemClick)="onButtonClick($event.itemData.hint)" ></dx-button-group> </div> </dxi-item> <dxi-item location="before" locateInMenu="auto" menuItemTemplate="menuSeparatorTemplate" > <div *dxTemplate> <div class="toolbar-separator"></div> </div> </dxi-item> <dxi-item location="before" locateInMenu="auto" widget="dxSelectBox"> <div *dxTemplate> <dx-select-box displayExpr="text" valueExpr="text" [inputAttr]="{ 'aria-label': 'Text Style' }" [value]="heading" [items]="headings" (onItemClick)="onHeadingClick()" ></dx-select-box> </div> </dxi-item> <dxi-item location="before" locateInMenu="auto" menuItemTemplate="menuSeparatorTemplate" > <div *dxTemplate> <div class="toolbar-separator"></div> </div> </dxi-item> <dxi-item location="before" locateInMenu="auto" widget="dxButton" showText="inMenu" > <div *dxTemplate> <dx-button icon="link" text="Link" [stylingMode]="stylingMode" (onClick)="onButtonClick('Link')" ></dx-button> </div> </dxi-item> <dxi-item location="before" locateInMenu="auto" widget="dxButton" showText="inMenu" > <div *dxTemplate> <dx-button icon="image" text="Add image" [stylingMode]="stylingMode" (onClick)="onButtonClick('Add Image')" ></dx-button> </div> </dxi-item> <dxi-item location="before" locateInMenu="auto" menuItemTemplate="menuSeparatorTemplate" > <div *dxTemplate> <div class="toolbar-separator"></div> </div> </dxi-item> <dxi-item location="before" locateInMenu="auto" widget="dxButton" showText="inMenu" > <div *dxTemplate> <dx-button icon="clearformat" text="Clear formating" [stylingMode]="stylingMode" (onClick)="onButtonClick('Clear Formating')" ></dx-button> </div> </dxi-item> <dxi-item location="before" locateInMenu="auto" widget="dxButton" showText="inMenu" > <div *dxTemplate> <dx-button icon="codeblock" text="Code block" [stylingMode]="stylingMode" (onClick)="onButtonClick('Code Block')" ></dx-button> </div> </dxi-item> <dxi-item location="before" locateInMenu="auto" widget="dxButton" showText="inMenu" > <div *dxTemplate> <dx-button icon="blockquote" text="Blockquote" [stylingMode]="stylingMode" (onClick)="onButtonClick('Blockquote')" ></dx-button> </div> </dxi-item> <dxi-item location="before" locateInMenu="auto" menuItemTemplate="menuSeparatorTemplate" > <div *dxTemplate> <div class="toolbar-separator"></div> </div> </dxi-item> <dxi-item location="after" widget="dxButton" showText="inMenu"> <div *dxTemplate> <dx-button icon="attach" text="Attach" [stylingMode]="stylingMode" (onClick)="onButtonClick('Attach')" ></dx-button> </div> </dxi-item> <dxi-item locateInMenu="always" widget="dxButton" showText="inMenu"> <div *dxTemplate> <dx-button icon="help" text="About" [stylingMode]="stylingMode" (onClick)="onButtonClick('About')" ></dx-button> </div> </dxi-item> <div *dxTemplate="let data of 'menuSeparatorTemplate'"> <div class="toolbar-menu-separator"></div> </div> <div *dxTemplate="let data of 'menuTextAlignTemplate'"> <dx-button-group keyExpr="alignment" stylingMode="outlined" [items]="textAlignItemsExtended" [selectedItemKeys]="selectedTextAlign" (onItemClick)="onTextAlignChanged($event)" ></dx-button-group> </div> </dx-toolbar> </dx-resizable> </div> <div class="options-container"> <div class="caption">Options</div> <dx-check-box [(value)]="toolbar.multiline" text="Multiline mode" ></dx-check-box> </div>
import { NgModule, Component, enableProdMode } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { DxToolbarModule, DxSelectBoxModule, DxTemplateModule, DxResizableModule, DxDropDownButtonModule, DxButtonModule, DxButtonGroupModule, DxCheckBoxModule, } from 'devextreme-angular'; import themes from 'devextreme/ui/themes'; import notify from 'devextreme/ui/notify'; import { FontFamily, FontSize, FontStyle, Heading, LineHeight, ListType, Service, TextAlign, TextAlignExtended, } from './app.service'; if (!/localhost/.test(document.location.host)) { enableProdMode(); } @Component({ selector: 'demo-app', templateUrl: 'app/app.component.html', styleUrls: ['app/app.component.css'], providers: [Service], }) export class AppComponent { stylingMode = !themes.current().startsWith('generic') ? 'text' : undefined; fontSizes: FontSize[] = this.service.getFontSizes(); lineHeights: LineHeight[] = this.service.getLineHeights(); lineHeight: number[] = [this.lineHeights[1].lineHeight]; fontFamilies: FontFamily[] = this.service.getFontFamilies(); headings: Heading[] = this.service.getHeadings(); heading = this.headings[0].text; fontStyles: FontStyle[] = this.service.getFontStyles(); textAlignItems: TextAlign[] = this.service.getTextAlign(); textAlignItemsExtended: TextAlignExtended[] = this.service.getTextAlignExtended(); selectedTextAlign = [this.textAlignItems[0].alignment]; listTypes: ListType[] = this.service.getListType(); constructor(private service: Service) {} onTextAlignChanged(e: { itemData: { hint: string } }): void { this.onButtonClick(e.itemData.hint); } onButtonClick(name: string) { notify(`The "${name}" button has been clicked`); } onSelectionChanged(name: string) { notify(`The "${name}" value has been changed`); } onFontFamilyClick() { notify('The "Font Family" value has been changed'); } onHeadingClick() { notify('The "Heading" value has been changed'); } } @NgModule({ imports: [ BrowserModule, DxToolbarModule, DxSelectBoxModule, DxTemplateModule, DxResizableModule, DxDropDownButtonModule, DxButtonModule, DxButtonGroupModule, DxCheckBoxModule, ], declarations: [AppComponent], bootstrap: [AppComponent], }) export class AppModule {} platformBrowserDynamic().bootstrapModule(AppModule);
:host { display: block; } ::ng-deep .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); } ::ng-deep .dx-resizable-handle-right::after { top: 50%; right: -5px; transform: translateY(-50%); } ::ng-deep .dx-toolbar.dx-toolbar-multiline .dx-toolbar-item { margin-bottom: 5px; } ::ng-deep .widget-container { margin-right: 10px; } ::ng-deep .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; } ::ng-deep .toolbar-separator { height: 36px; margin: 0 5px; border-left: 1px solid #ddd; } ::ng-deep .toolbar-menu-separator { height: 1px; border-bottom: 1px solid #ddd; }
import { Injectable } from '@angular/core'; export class FontSize { size: number; text: string; } export class LineHeight { lineHeight: number; text: string; } export class FontFamily { text: string; } export class Heading { text: string; } export class FontStyle { icon: string; hint: string; } export class TextAlign { icon: string; alignment: string; hint: string; } export class TextAlignExtended extends TextAlign { text: string; } export class ListType { icon: string; alignment: string; hint: string; } const fontSizes: FontSize[] = [ { size: 10, text: '10px' }, { size: 12, text: '12px' }, { size: 14, text: '14px' }, { size: 16, text: '16px' }, { size: 18, text: '18px' }, ]; const lineHeights: LineHeight[] = [ { lineHeight: 1, text: '1' }, { lineHeight: 1.35, text: '1.35' }, { lineHeight: 1.5, text: '1.5' }, { lineHeight: 2, text: '2' }, ]; const fontFamilies: FontFamily[] = [ { text: 'Arial' }, { text: 'Courier New' }, { text: 'Georgia' }, { text: 'Impact' }, { text: 'Lucida Console' }, { text: 'Tahoma' }, { text: 'Times New Roman' }, ]; const headings: Heading[] = [ { text: 'Normal text' }, { text: 'Heading 1' }, { text: 'Heading 2' }, { text: 'Heading 3' }, { text: 'Heading 4' }, { text: 'Heading 5' }, ]; const fontStyles: FontStyle[] = [ { icon: 'bold', hint: 'Bold', }, { icon: 'italic', hint: 'Italic', }, { icon: 'underline', hint: 'Underlined', }, { icon: 'strike', hint: 'Strikethrough', }, ]; const textAlignsExtended: TextAlignExtended[] = [ { 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', }, ]; const listTypes: ListType[] = [ { icon: 'orderedlist', alignment: 'orderedlist', hint: 'Ordered', }, { icon: 'bulletlist', alignment: 'bulletlist', hint: 'Bullet', }, ]; @Injectable() export class Service { getFontSizes(): FontSize[] { return fontSizes; } getLineHeights(): LineHeight[] { return lineHeights; } getFontFamilies(): FontFamily[] { return fontFamilies; } getHeadings(): Heading[] { return headings; } getFontStyles(): FontStyle[] { return fontStyles; } getTextAlign(): TextAlign[] { return textAlignsExtended.map( ({ icon, alignment, hint }) => ({ icon, alignment, hint }), ); } getTextAlignExtended(): TextAlignExtended[] { return textAlignsExtended; } getListType(): ListType[] { return listTypes; } }
// In real applications, you should not transpile code in the browser. // You can see how to create your own application with Angular and DevExtreme here: // https://js.devexpress.com/Documentation/Guide/Angular_Components/Getting_Started/Create_a_DevExtreme_Application/ const componentNames = [ 'accordion', 'action-sheet', 'autocomplete', 'bar-gauge', 'box', 'bullet', 'button-group', 'button', 'calendar', 'chart', 'check-box', 'circular-gauge', 'color-box', 'context-menu', 'data-grid', 'date-box', 'date-range-box', 'defer-rendering', 'diagram', 'draggable', 'drawer', 'drop-down-box', 'drop-down-button', 'file-manager', 'file-uploader', 'filter-builder', 'form', 'funnel', 'gallery', 'gantt', 'html-editor', 'linear-gauge', 'list', 'load-indicator', 'load-panel', 'lookup', 'map', 'menu', 'multi-view', 'nested', 'number-box', 'pie-chart', 'pivot-grid-field-chooser', 'pivot-grid', 'polar-chart', 'popover', 'popup', 'progress-bar', 'radio-group', 'range-selector', 'range-slider', 'recurrence-editor', 'resizable', 'responsive-box', 'sankey', 'scheduler', 'scroll-view', 'select-box', 'slider', 'sortable', 'sparkline', 'speed-dial-action', 'splitter', 'switch', 'tab-panel', 'tabs', 'tag-box', 'text-area', 'text-box', 'tile-view', 'toast', 'toolbar', 'tooltip', 'tree-list', 'tree-map', 'tree-view', 'validation-group', 'validation-summary', 'validator', 'vector-map', ]; window.exports = window.exports || {}; window.config = { transpiler: 'ts', typescriptOptions: { module: 'system', emitDecoratorMetadata: true, experimentalDecorators: true, }, meta: { 'typescript': { 'exports': 'ts', }, 'devextreme/time_zone_utils.js': { 'esModule': true, }, 'devextreme/localization.js': { 'esModule': true, }, 'devextreme/viz/palette.js': { 'esModule': true, }, '@angular/platform-browser-dynamic': { 'esModule': true, }, '@angular/platform-browser': { 'esModule': true, }, '@angular/core': { 'esModule': true, }, '@angular/common': { 'esModule': true, }, '@angular/animations': { 'esModule': true, }, '@angular/forms': { 'esModule': true, }, }, paths: { 'npm:': 'https://unpkg.com/', 'bundles:': '../../../../bundles/', }, map: { 'ts': 'npm:plugin-typescript@4.2.4/lib/plugin.js', 'typescript': 'npm:typescript@4.2.4/lib/typescript.js', /* @angular */ '@angular/compiler': 'bundles:@angular/compiler.umd.js', '@angular/platform-browser-dynamic': 'bundles:@angular/platform-browser-dynamic.umd.js', '@angular/core': 'bundles:@angular/core.umd.js', '@angular/core/primitives/signals': 'bundles:@angular/core.primitives.signals.umd.js', '@angular/common': 'bundles:@angular/common.umd.js', '@angular/common/http': 'bundles:@angular/common-http.umd.js', '@angular/platform-browser': 'bundles:@angular/platform-browser.umd.js', '@angular/platform-browser/animations': 'bundles:@angular/platform-browser.umd.js', '@angular/forms': 'bundles:@angular/forms.umd.js', /* devextreme */ 'devextreme': 'npm:devextreme@24.1.3/cjs', '@devextreme/runtime': 'npm:@devextreme/runtime@3.0.13', 'devextreme/bundles/dx.all': 'npm:devextreme@24.1.3/bundles/dx.all.js', 'devextreme-quill': 'npm:devextreme-quill@1.7.1/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.2.8', 'devexpress-gantt': 'npm:devexpress-gantt@4.1.56', /* devextreme-angular umd maps */ 'devextreme-angular': 'bundles:devextreme-angular/devextreme-angular.umd.js', 'devextreme-angular/core': 'bundles:devextreme-angular/devextreme-angular-core.umd.js', ...componentNames.reduce((acc, name) => { acc[`devextreme-angular/ui/${name}`] = `bundles:devextreme-angular/devextreme-angular-ui-${name}.umd.js`; return acc; }, {}), 'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js', 'tslib': 'npm:tslib@2.6.1/tslib.js', 'rxjs': 'npm:rxjs@7.5.3/dist/bundles/rxjs.umd.js', 'rxjs/operators': 'npm:rxjs@7.5.3/dist/cjs/operators/index.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', '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', // Prettier 'prettier/standalone': 'npm:prettier@2.8.8/standalone.js', 'prettier/parser-html': 'npm:prettier@2.8.8/parser-html.js', }, packages: { 'app': { main: './app.component.ts', defaultExtension: 'ts', }, 'devextreme': { defaultExtension: 'js', }, 'devextreme/events/utils': { main: 'index', }, 'devextreme/events': { main: 'index', }, 'es6-object-assign': { main: './index.js', defaultExtension: 'js', }, 'rxjs': { defaultExtension: 'js', }, 'rxjs/operators': { defaultExtension: 'js', }, }, packageConfigPaths: [ 'npm:@devextreme/*/package.json', 'npm:@devextreme/runtime@3.0.13/inferno/package.json', 'npm:rxjs@7.5.3/package.json', 'npm:rxjs@7.5.3/operators/package.json', 'npm:devexpress-diagram@2.2.8/package.json', 'npm:devexpress-gantt@4.1.56/package.json', ], }; System.config(window.config); // System.import('@angular/compiler').catch(console.error.bind(console));
<!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" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/24.1.3/css/dx.light.css" /> <script src="https://unpkg.com/core-js@2.6.12/client/shim.min.js"></script> <script src="https://unpkg.com/zone.js@0.13.0/dist/zone.js"></script> <script src="https://unpkg.com/reflect-metadata@0.1.13/Reflect.js"></script> <script src="https://unpkg.com/systemjs@0.21.3/dist/system.js"></script> <script src="config.js"></script> <script> System.import("app").catch(console.error.bind(console)); </script> </head> <body class="dx-viewport"> <div class="demo-container"> <demo-app>Loading...</demo-app> </div> </body> </html>

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.