If you have technical questions, please create a support ticket in the DevExpress Support Center.
import React from 'react';
import Splitter, { Item } from 'devextreme-react/splitter';
import PaneContent from './PaneContent.tsx';
const PaneContentWithTitle = (title: string, initialSize?: string) => (data) => (<PaneContent title={title} {data} size={initialSize} />);
const App = () => (
<React.Fragment>
<Splitter
id="splitter"
>
<Item
resizable={true}
size="140px"
minSize="70px"
render={PaneContentWithTitle('Left Pane', '140px')}
/>
<Item
resizable={true}
>
<Splitter
orientation="vertical"
>
<Item
resizable={true}
collapsible={true}
maxSize="75%"
collapsedSize="8%"
render={PaneContentWithTitle('Central Pane')}
/>
<Item
resizable={true}
collapsible={true}
>
<Splitter>
<Item
resizable={true}
collapsible={true}
size="30%"
minSize="5%"
render={PaneContentWithTitle('Nested Left Pane', '30%')}
/>
<Item
resizable={true}
render={PaneContentWithTitle('Nested Central Pane')}
/>
<Item
resizable={true}
collapsible={true}
size="30%"
minSize="5%"
render={PaneContentWithTitle('Nested Right Pane', '30%')}
/>
</Splitter>
</Item>
</Splitter>
</Item>
<Item
resizable={false}
collapsible={false}
size="140px"
render={PaneContentWithTitle('Right Pane', '140px')}
/>
</Splitter>
</React.Fragment>
);
export default App;
xxxxxxxxxx
import React from 'react';
import Splitter, { Item } from 'devextreme-react/splitter';
import PaneContent from './PaneContent.js';
const PaneContentWithTitle = (title, initialSize) => (data) =>
(
<PaneContent
title={title}
{data}
size={initialSize}
/>
);
const App = () => (
<React.Fragment>
<Splitter id="splitter">
<Item
resizable={true}
size="140px"
minSize="70px"
render={PaneContentWithTitle('Left Pane', '140px')}
/>
<Item resizable={true}>
<Splitter orientation="vertical">
<Item
resizable={true}
collapsible={true}
maxSize="75%"
collapsedSize="8%"
render={PaneContentWithTitle('Central Pane')}
/>
<Item
resizable={true}
collapsible={true}
>
<Splitter>
<Item
resizable={true}
collapsible={true}
size="30%"
minSize="5%"
render={PaneContentWithTitle('Nested Left Pane', '30%')}
/>
<Item
resizable={true}
render={PaneContentWithTitle('Nested Central Pane')}
/>
<Item
resizable={true}
collapsible={true}
size="30%"
minSize="5%"
render={PaneContentWithTitle('Nested Right Pane', '30%')}
/>
</Splitter>
</Item>
</Splitter>
</Item>
<Item
resizable={false}
collapsible={false}
size="140px"
render={PaneContentWithTitle('Right Pane', '140px')}
/>
</Splitter>
</React.Fragment>
);
export default App;
xxxxxxxxxx
import React, { useRef, useEffect } from 'react';
const dimensionOptions = new Set(['size', 'minSize', 'maxSize', 'collapsedSize']);
const getPaneState = (data): 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}`;
};
const getFilteredDimensionOptions = (data) => Object.entries(data)
.filter(([key, value]) => dimensionOptions.has(key) && value)
.map(([key, value]) => ({ key, value }));
const PaneContent = (data: any) => {
const paneContentRef = useRef(null);
useEffect(() => {
const element = paneContentRef.current.parentNode;
element.setAttribute('tabIndex', '0');
});
return (
<div ref={paneContentRef} className="pane-content">
<div className="pane-title">{data.title}</div>
<div className="pane-state">{getPaneState(data)}</div>
{getFilteredDimensionOptions(data).map((item, index) => (
<div className="pane-option" key={index}>
{item.key}: {item.value}
</div>
))}
</div>
);
};
export default PaneContent;
xxxxxxxxxx
import React from 'react';
import ReactDOM from 'react-dom';
import themes from 'devextreme/ui/themes';
import App from './App.tsx';
themes.initialized(() => {
ReactDOM.render(
<App />,
document.getElementById('app'),
);
});
xxxxxxxxxx
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://unpkg.com/',
'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',
'devextreme-quill': 'npm:devextreme-quill@1.7.1/dist/dx-quill.min.js',
'devexpress-diagram': 'npm:devexpress-diagram@2.2.5/dist/dx-diagram.js',
'devexpress-gantt': 'npm:devexpress-gantt@4.1.54/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/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.8/standalone.js',
'prettier/parser-html': 'npm:prettier@2.8.8/parser-html.js',
},
packages: {
'devextreme': {
defaultExtension: 'js',
},
'devextreme-react': {
main: 'index.js',
},
'devextreme/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',
'npm:@devextreme/runtime@3.0.12/inferno/package.json',
],
babelOptions: {
sourceMaps: false,
stage0: true,
react: true,
},
};
System.config(window.config);
xxxxxxxxxx
import React, { useRef, useEffect } from 'react';
const dimensionOptions = new Set(['size', 'minSize', 'maxSize', 'collapsedSize']);
const getPaneState = (data) => {
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}`;
};
const getFilteredDimensionOptions = (data) =>
Object.entries(data)
.filter(([key, value]) => dimensionOptions.has(key) && value)
.map(([key, value]) => ({ key, value }));
const PaneContent = (data) => {
const paneContentRef = useRef(null);
useEffect(() => {
const element = paneContentRef.current.parentNode;
element.setAttribute('tabIndex', '0');
});
return (
<div
ref={paneContentRef}
className="pane-content"
>
<div className="pane-title">{data.title}</div>
<div className="pane-state">{getPaneState(data)}</div>
{getFilteredDimensionOptions(data).map((item, index) => (
<div
className="pane-option"
key={index}
>
{item.key}: {item.value}
</div>
))}
</div>
);
};
export default PaneContent;
xxxxxxxxxx
import React from 'react';
import ReactDOM from 'react-dom';
import themes from 'devextreme/ui/themes';
import App from './App.js';
themes.initialized(() => {
ReactDOM.render(<App />, document.getElementById('app'));
});
xxxxxxxxxx
<html lang="en">
<head></head>
<body class="dx-viewport">
<div class="demo-container">
<div id="app"></div>
</div>
</body>
</html>
xxxxxxxxxx
.demo-container {
height: 500px;
}
#app {
height: 100%;
}
#splitter {
border: 1px solid var(--dx-color-border);
border-radius: 8px;
overflow: hidden;
}
.pane-content {
padding: 12px;
}
.pane-title {
font-weight: 600;
margin-bottom: 2px;
}
.pane-state {
font-size: var(--dx-font-size-xs);
margin-bottom: 4px;
}
.pane-option {
color: var(--dx-texteditor-color-label);
font-size: 10px;
}
#splitter > .dx-splitter-item:first-child > .dx-splitter-item-content:focus {
border-start-start-radius: 8px;
border-end-start-radius: 8px;
}
#splitter > .dx-splitter-item:last-child > .dx-splitter-item-content:focus {
border-end-end-radius: 8px;
border-start-end-radius: 8px;
}
.dx-splitter-item-content:focus {
outline: none;
box-shadow: inset 0 0 0 1px var(--dx-color-primary);
}
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.