DevExtreme v24.1 is now available.

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

Your search did not match any results.

Angular Splitter

You can use our Splitter UI widgets to create resizable panes within your DevExtreme-powered web app/page.

To get started with DevExtreme Splitter, refer to the following tutorial for step-by-step instructions: Getting Started with Splitter.

DevExtreme Accessibility Compliance
DevExtreme component libraries meet a variety of WCAG and Section 508 compliance standards. To assess this demo’s accessibility level, click the Run AXE® Validation button to launch the AXE® web accessibility evaluation tool.
All trademarks or registered trademarks are property of their respective owners. AXE® Terms of Use
The overall accessibility level of your application depends on the Splitter features used.
Backend API
<dx-splitter id="splitter"> <dxi-item [resizable]="true" minSize="70px" size="140px" template="Left Pane" ></dxi-item> <dxi-item [resizable]="true"> <dx-splitter orientation="vertical"> <dxi-item [resizable]="true" [collapsible]="true" collapsedSize="8%" maxSize="75%" template="Central Pane" ></dxi-item> <dxi-item [resizable]="true" [collapsible]="true"> <dx-splitter> <dxi-item [resizable]="true" [collapsible]="true" minSize="5%" size="30%" template="Nested Left Pane" ></dxi-item> <dxi-item [resizable]="true" template="Nested Central Pane" ></dxi-item> <dxi-item [resizable]="true" [collapsible]="true" minSize="5%" size="30%" template="Nested Right Pane" ></dxi-item> <ng-container *ngFor="let pane of paneContentTemplates"> <div *dxTemplate="let data of pane.name" tabindex="0"> <ng-template [ngTemplateOutlet]="customPaneTemplate" [ngTemplateOutletContext]="{ data: data, title: pane.name }" > </ng-template> </div> </ng-container> </dx-splitter> </dxi-item> <ng-container *ngFor="let pane of paneContentTemplates"> <div *dxTemplate="let data of pane.name" tabindex="0"> <ng-template [ngTemplateOutlet]="customPaneTemplate" [ngTemplateOutletContext]="{ data: data, title: pane.name }" > </ng-template> </div> </ng-container> </dx-splitter> </dxi-item> <dxi-item [resizable]="false" [collapsible]="false" size="140px" template="Right Pane" ></dxi-item> <ng-container *ngFor="let pane of paneContentTemplates"> <div *dxTemplate="let data of pane.name" tabindex="0"> <ng-template [ngTemplateOutlet]="customPaneTemplate" [ngTemplateOutletContext]="{ data: data, title: pane.name }" > </ng-template> </div> </ng-container> </dx-splitter> <ng-template #customPaneTemplate let-data="data" let-title="title"> <div class="pane-content"> <div class="pane-title">{{ title }}</div> <div class="pane-state">{{ getPaneState(data) }}</div> <ng-container *ngFor="let item of filterDimensionOptions(data)"> <div class="pane-option">{{ item.key }}: {{ item.value }}</div> </ng-container> </div> </ng-template>
import { NgModule, ChangeDetectionStrategy, Component, ViewChild, enableProdMode, Input, } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { DxSplitterModule } from 'devextreme-angular'; if (!document.location.host.includes('localhost')) { enableProdMode(); } interface PaneContentTemplate { name: string; data?: any; } @Component({ selector: 'demo-app', templateUrl: `app/app.component.html`, styleUrls: [`app/app.component.css`], changeDetection: ChangeDetectionStrategy.OnPush, }) export class AppComponent { dimensionOptions = new Set(['size', 'minSize', 'maxSize', 'collapsedSize']); paneContentTemplates: PaneContentTemplate[] = [ { name: 'Left Pane' }, { name: 'Central Pane' }, { name: 'Right Pane' }, { name: 'Nested Left Pane' }, { name: 'Nested Central Pane' }, { name: 'Nested Right Pane' }, ]; getPaneState(data: any): string { if (data.resizable !== false && !data.collapsible) { return 'Resizable only'; } const resizableText = data.resizable ? 'Resizable' : 'Non-resizable'; const collapsibleText = data.collapsible ? 'collapsible' : 'non-collapsible'; return `${resizableText} and ${collapsibleText}`; } filterDimensionOptions(data: any): { key: string; value: any }[] { return Object.entries(data) .reverse() .filter(([key]) => this.dimensionOptions.has(key)) .map(([key, value]) => ({ key, value })); } } @NgModule({ imports: [ BrowserModule, DxSplitterModule, ], declarations: [AppComponent], bootstrap: [AppComponent], }) export class AppModule { } platformBrowserDynamic().bootstrapModule(AppModule);
::ng-deep .demo-container { height: 500px; } ::ng-deep #splitter { border: 1px solid var(--dx-color-border); border-radius: 8px; overflow: hidden; } ::ng-deep .pane-content { padding: 12px; } ::ng-deep .pane-title { font-weight: 600; margin-bottom: 2px; } ::ng-deep .pane-state { font-size: var(--dx-font-size-xs); margin-bottom: 4px; } ::ng-deep .pane-option { color: var(--dx-texteditor-color-label); font-size: 10px; } ::ng-deep #splitter > .dx-splitter-item:first-child > .dx-splitter-item-content:focus { border-start-start-radius: 8px; border-end-start-radius: 8px; } ::ng-deep #splitter > .dx-splitter-item:last-child > .dx-splitter-item-content:focus { border-end-end-radius: 8px; border-start-end-radius: 8px; } ::ng-deep .dx-splitter-item-content:focus { outline: none; box-shadow: inset 0 0 0 1px var(--dx-color-primary); }
// 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/common/http': { 'esModule': true, }, '@angular/compiler': { '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.6/cjs', '@devextreme/runtime': 'npm:@devextreme/runtime@3.0.13', 'devextreme/bundles/dx.all': 'npm:devextreme@24.1.6/bundles/dx.all.js', 'devextreme-quill': 'npm:devextreme-quill@1.7.1/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.2.11', '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', 'devextreme-angular/http': 'bundles:devextreme-angular/devextreme-angular-http.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.11/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.6/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.3/bundles/zone.umd.min.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>

To specify individual splitter panes, set the items or dataSource property. Use dataSource if data is remote or should be processed. If you specify multiple panes, they will appear one after another with splitters between them.

The following base options are available for a pane:

  • resizable (default: true)
    If true, a handle appears at the side of the pane. Drag the handle to adjust pane size.

  • collapsible (default: false)
    If true, an arrow appears on the handle. Click the arrow to close the pane.

  • collapsed (default: false)
    Specifies whether the pane is initially collapsed.

To configure the layout of the Splitter component, you can specify its orientation as 'vertical' or 'horizontal' (default). All Splitter "size" properties depend on the orientation. If it is 'horizontal', "size" is the width. Otherwise, it is height. The following pane "size" properties can be specified:

  • size
    Initial pane width/height.

  • minSize
    Minimum width/height for a resizable pane.

  • maxSize
    Maximum width/height for a resizable pane.

  • collapsedSize
    The width/height of a collapsible pane when collapsed.

You can also place one Splitter inside another to create nested layouts. To do so, use the pane's splitter property.

Splitter panes can include different content types, from simple HTML markup to components. You can declare HTML markup inside the item tag or use the following properties to populate panes with content:

  • itemTemplate
    Specifies a custom template for all panes.

  • template
    Specifies a custom template for an individual pane.