If you have technical questions, please create a support ticket in the DevExpress Support Center.
import React, { useCallback, useState } from 'react';
import Accordion, { AccordionTypes } from 'devextreme-react/accordion';
import CheckBox, { CheckBoxTypes } from 'devextreme-react/check-box';
import TagBox, { TagBoxTypes } from 'devextreme-react/tag-box';
import Slider, { Tooltip, Label, SliderTypes } from 'devextreme-react/slider';
import service from './data.ts';
import CustomTitle from './CustomTitle.tsx';
import CustomItem from './CustomItem.tsx';
const companyLabel = { 'aria-label': 'Company' };
const companies = service.getCompanies();
const App = () => {
const [selectedItems, setSelectedItems] = useState([companies[0]]);
const [multiple, setMultiple] = useState(false);
const [collapsible, setCollapsible] = useState(false);
const [animationDuration, setAnimationDuration] = useState(300);
const selectionChanged = useCallback((e: AccordionTypes.SelectionChangedEvent) => {
let newItems = [selectedItems];
e.removedItems.forEach((item) => {
const index = newItems.indexOf(item);
if (index >= 0) {
newItems.splice(index, 1);
}
});
if (e.addedItems.length) {
newItems = [newItems, e.addedItems];
}
setSelectedItems(newItems);
}, [selectedItems, setSelectedItems]);
const selectedItemsChanged = useCallback((e: TagBoxTypes.ValueChangedEvent) => {
setSelectedItems(e.value);
}, [setSelectedItems]);
const multipleChanged = useCallback((e: CheckBoxTypes.ValueChangedEvent) => {
setMultiple(e.value);
}, [setMultiple]);
const collapsibleChanged = useCallback((e: CheckBoxTypes.ValueChangedEvent) => {
setCollapsible(e.value);
}, [setCollapsible]);
const animationDurationChanged = useCallback((e: SliderTypes.ValueChangedEvent) => {
setAnimationDuration(e.value);
}, [setAnimationDuration]);
return (
<div id="accordion">
<Accordion
dataSource={companies}
collapsible={collapsible}
multiple={multiple}
animationDuration={animationDuration}
selectedItems={selectedItems}
onSelectionChanged={selectionChanged}
itemTitleRender={CustomTitle}
itemRender={CustomItem}
id="accordion-container"
/>
<div className="options">
<div className="caption">Options</div>
<div className="option">
<CheckBox
text="Multiple enabled"
value={multiple}
onValueChanged={multipleChanged}
/>
</div>
<div className="option">
<CheckBox
text="Collapsible enabled"
value={collapsible}
onValueChanged={collapsibleChanged}
/>
</div>
<div className="option">
<span>Animation duration</span>
<Slider
min={0}
max={1000}
value={animationDuration}
onValueChanged={animationDurationChanged}
>
<Tooltip enabled={true} position="bottom" />
<Label visible={true} />
</Slider>
</div>
<div className="option">
<span className="caption">Selected Items</span>
<TagBox
dataSource={companies}
displayExpr="CompanyName"
value={selectedItems}
inputAttr={companyLabel}
onValueChanged={selectedItemsChanged}
disabled={!multiple}
/>
</div>
</div>
</div>
);
};
export default App;
xxxxxxxxxx
import React, { useCallback, useState } from 'react';
import Accordion from 'devextreme-react/accordion';
import CheckBox from 'devextreme-react/check-box';
import TagBox from 'devextreme-react/tag-box';
import Slider, { Tooltip, Label } from 'devextreme-react/slider';
import service from './data.js';
import CustomTitle from './CustomTitle.js';
import CustomItem from './CustomItem.js';
const companyLabel = { 'aria-label': 'Company' };
const companies = service.getCompanies();
const App = () => {
const [selectedItems, setSelectedItems] = useState([companies[0]]);
const [multiple, setMultiple] = useState(false);
const [collapsible, setCollapsible] = useState(false);
const [animationDuration, setAnimationDuration] = useState(300);
const selectionChanged = useCallback(
(e) => {
let newItems = [selectedItems];
e.removedItems.forEach((item) => {
const index = newItems.indexOf(item);
if (index >= 0) {
newItems.splice(index, 1);
}
});
if (e.addedItems.length) {
newItems = [newItems, e.addedItems];
}
setSelectedItems(newItems);
},
[selectedItems, setSelectedItems],
);
const selectedItemsChanged = useCallback(
(e) => {
setSelectedItems(e.value);
},
[setSelectedItems],
);
const multipleChanged = useCallback(
(e) => {
setMultiple(e.value);
},
[setMultiple],
);
const collapsibleChanged = useCallback(
(e) => {
setCollapsible(e.value);
},
[setCollapsible],
);
const animationDurationChanged = useCallback(
(e) => {
setAnimationDuration(e.value);
},
[setAnimationDuration],
);
return (
<div id="accordion">
<Accordion
dataSource={companies}
collapsible={collapsible}
multiple={multiple}
animationDuration={animationDuration}
selectedItems={selectedItems}
onSelectionChanged={selectionChanged}
itemTitleRender={CustomTitle}
itemRender={CustomItem}
id="accordion-container"
/>
<div className="options">
<div className="caption">Options</div>
<div className="option">
<CheckBox
text="Multiple enabled"
value={multiple}
onValueChanged={multipleChanged}
/>
</div>
<div className="option">
<CheckBox
text="Collapsible enabled"
value={collapsible}
onValueChanged={collapsibleChanged}
/>
</div>
<div className="option">
<span>Animation duration</span>
<Slider
min={0}
max={1000}
value={animationDuration}
onValueChanged={animationDurationChanged}
>
<Tooltip
enabled={true}
position="bottom"
/>
<Label visible={true} />
</Slider>
</div>
<div className="option">
<span className="caption">Selected Items</span>
<TagBox
dataSource={companies}
displayExpr="CompanyName"
value={selectedItems}
inputAttr={companyLabel}
onValueChanged={selectedItemsChanged}
disabled={!multiple}
/>
</div>
</div>
</div>
);
};
export default App;
xxxxxxxxxx
import React from 'react';
export default function CustomItem(data) {
return (
<div>
<div>
<p>
<b>{data.City} </b>
(<span>{data.State}</span>)
</p>
<p>
<span>{data.Zipcode} </span>
<span>{data.Address}</span>
</p>
</div>
<div>
<p>
Phone: <b>{data.Phone}</b>
</p>
<p>
Fax: <b>{data.Fax}</b>
</p>
<p>
Website: <a href={data.Website} target="_blank">
{data.Website}
</a>
</p>
</div>
</div>
);
}
xxxxxxxxxx
import React from 'react';
export default function CustomTitle(data) {
return (
<div className='header'>{data.CompanyName}</div>
);
}
xxxxxxxxxx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.tsx';
ReactDOM.render(
<App />,
document.getElementById('app'),
);
xxxxxxxxxx
const companies = [{
ID: 1,
CompanyName: 'Super Mart of the West',
Address: '702 SW 8th Street',
City: 'Bentonville',
State: 'Arkansas',
Zipcode: 72716,
Phone: '(800) 555-2797',
Fax: '(800) 555-2171',
Website: 'http://www.nowebsitesupermart.dx',
}, {
ID: 2,
CompanyName: 'Electronics Depot',
Address: '2455 Paces Ferry Road NW',
City: 'Atlanta',
State: 'Georgia',
Zipcode: 30339,
Phone: '(800) 595-3232',
Fax: '(800) 595-3231',
Website: 'http://www.nowebsitedepot.dx',
}, {
ID: 3,
CompanyName: 'K&S Music',
Address: '1000 Nicllet Mall',
City: 'Minneapolis',
State: 'Minnesota',
Zipcode: 55403,
Phone: '(612) 304-6073',
Fax: '(612) 304-6074',
Website: 'http://www.nowebsitemusic.dx',
}, {
ID: 4,
CompanyName: "Tom's Club",
Address: '999 Lake Drive',
City: 'Issaquah',
State: 'Washington',
Zipcode: 98027,
Phone: '(800) 955-2292',
Fax: '(800) 955-2293',
Website: 'http://www.nowebsitetomsclub.dx',
}];
export default {
getCompanies() {
return companies;
},
};
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 from 'react';
export default function CustomItem(data) {
return (
<div>
<div>
<p>
<b>{data.City} </b>(<span>{data.State}</span>)
</p>
<p>
<span>{data.Zipcode} </span>
<span>{data.Address}</span>
</p>
</div>
<div>
<p>
Phone: <b>{data.Phone}</b>
</p>
<p>
Fax: <b>{data.Fax}</b>
</p>
<p>
Website:{' '}
<a
href={data.Website}
target="_blank"
>
{data.Website}
</a>
</p>
</div>
</div>
);
}
xxxxxxxxxx
import React from 'react';
export default function CustomTitle(data) {
return <div className="header">{data.CompanyName}</div>;
}
xxxxxxxxxx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.js';
ReactDOM.render(<App />, document.getElementById('app'));
xxxxxxxxxx
const companies = [
{
ID: 1,
CompanyName: 'Super Mart of the West',
Address: '702 SW 8th Street',
City: 'Bentonville',
State: 'Arkansas',
Zipcode: 72716,
Phone: '(800) 555-2797',
Fax: '(800) 555-2171',
Website: 'http://www.nowebsitesupermart.dx',
},
{
ID: 2,
CompanyName: 'Electronics Depot',
Address: '2455 Paces Ferry Road NW',
City: 'Atlanta',
State: 'Georgia',
Zipcode: 30339,
Phone: '(800) 595-3232',
Fax: '(800) 595-3231',
Website: 'http://www.nowebsitedepot.dx',
},
{
ID: 3,
CompanyName: 'K&S Music',
Address: '1000 Nicllet Mall',
City: 'Minneapolis',
State: 'Minnesota',
Zipcode: 55403,
Phone: '(612) 304-6073',
Fax: '(612) 304-6074',
Website: 'http://www.nowebsitemusic.dx',
},
{
ID: 4,
CompanyName: "Tom's Club",
Address: '999 Lake Drive',
City: 'Issaquah',
State: 'Washington',
Zipcode: 98027,
Phone: '(800) 955-2292',
Fax: '(800) 955-2293',
Website: 'http://www.nowebsitetomsclub.dx',
},
];
export default {
getCompanies() {
return companies;
},
};
xxxxxxxxxx
<html lang="en">
<head></head>
<body class="dx-viewport">
<div class="demo-container">
<div id="app"></div>
</div>
</body>
</html>
xxxxxxxxxx
#accordion {
height: 700px;
}
#accordion .header {
font-size: 20px;
}
#accordion .header,
#accordion p {
margin: 0;
}
#accordion-container {
margin-right: 400px;
}
.dx-theme-material #accordion .dx-accordion-item-title {
display: flex;
}
.dx-theme-material #accordion .header {
align-self: center;
}
.options {
padding: 20px;
position: absolute;
bottom: 0;
right: 0;
width: 340px;
top: 0;
background-color: rgba(191, 191, 191, 0.15);
}
.options > .caption {
font-weight: 500;
font-size: 18px;
}
.option {
margin-top: 10px;
}
.option > .caption {
margin-top: 10px;
display: inline-block;
}
.option > .dx-tagbox {
margin-top: 2px;
}
Bind Accordion to Data
You can display Accordion items from the items array or a dataSource. If you use the items array, specify the title and text properties.
Configure Item Selection and Collapsibility
Enable the multiple property to allow users to select multiple panels. Use the selectedItems array to store selected items. Toggle the "Multiple enabled" checkbox in the Options demo section to see how it affects the selection.
If you want to allow users to close panels on click, set the collapsible property to true. Check the "Collapsible enabled" checkbox in the Options demo section to enable this feature.
Configure Animation
The animationDuration property allows you to specify the animation duration when users expand/collapse a panel. Use the "Animation duration" slider in the Options demo section to see how it affects the animation.
Customize Item Appearance
Use the itemTemplate and itemTitleTemplate properties to customize the panel appearance. If you use the items array, you can also specify the icon property.