EN
React - simple animated expander example
9 points
In this short article we would like to show how to create simple exander component in React.
xxxxxxxxxx
1
//Note: Uncomment import lines during working with JSX Compiler.
2
// import React from 'react';
3
// import ReactDOM from 'react-dom';
4
5
const expanderStyle = {
6
margin: '6px 0',
7
padding: '2px',
8
border: '1px solid silver'
9
};
10
11
const headerStyle = {
12
display: 'flex',
13
cursor: 'pointer'
14
};
15
16
const titleStyle = {
17
padding: '3px',
18
flex: 'none'
19
};
20
21
const spacerStyle = {
22
flex: '1'
23
};
24
25
const iconStyle = {
26
padding: '3px',
27
flex: 'none'
28
};
29
30
const contentStyle = {
31
overflow: 'hidden',
32
transition: 'all 0.3s'
33
};
34
35
const contentExpandedStyle = {
36
contentStyle,
37
padding: '4px 0',
38
border: '1px solid silver',
39
height: 'auto',
40
filter: 'opacity(1)'
41
};
42
43
const contentCollapsedStyle = {
44
contentStyle,
45
padding: '0 0',
46
border: '1px solid transparent',
47
height: '0',
48
filter: 'opacity(0)'
49
};
50
51
const Expander = ({title, children}) => {
52
const [expanded, setExpanded] = React.useState(false);
53
const handleHeaderClick = () => {
54
setExpanded(expanded => !expanded);
55
};
56
return (
57
<div style={expanderStyle}>
58
<div style={headerStyle} onClick={handleHeaderClick}>
59
<div style={titleStyle}>{title}</div>
60
<div style={spacerStyle} />
61
<div style={iconStyle}>{expanded ? '△' : '▽'}</div>
62
</div>
63
<div style={expanded ? contentExpandedStyle : contentCollapsedStyle}>
64
{children}
65
</div>
66
</div>
67
);
68
};
69
70
// Usage example:
71
72
const App = () => {
73
return (
74
<div style={{height: '260px'}}>
75
<Expander title="🍏🍌🍊 Fruits">
76
<ul>
77
<li>🍏 Apple</li>
78
<li>🍌 Banana</li>
79
<li>🍊 Orange</li>
80
</ul>
81
</Expander>
82
<Expander title="🥕🥒🍅 Vegetables">
83
<ul>
84
<li>🥕 Carrot</li>
85
<li>🥒 Cucumber</li>
86
<li>🍅 Tomato</li>
87
</ul>
88
</Expander>
89
</div >
90
);
91
};
92
93
const root = document.querySelector('#root');
94
ReactDOM.render(<App/>, root );
In this section expander items use common context to do not let expand more than one item in xsame time.
xxxxxxxxxx
1
//Note: Uncomment import lines during working with JSX Compiler.
2
// import React from 'react';
3
// import ReactDOM from 'react-dom';
4
5
const expanderStyle = {
6
padding: '0 2px',
7
border: '1px solid silver'
8
};
9
10
const itemStyle = {
11
margin: '2px 0',
12
padding: '2px',
13
border: '1px solid silver'
14
};
15
16
const headerStyle = {
17
display: 'flex',
18
cursor: 'pointer'
19
};
20
21
const titleStyle = {
22
padding: '3px',
23
flex: 'none'
24
};
25
26
const spacerStyle = {
27
flex: '1'
28
};
29
30
const iconStyle = {
31
padding: '3px',
32
flex: 'none'
33
};
34
35
const contentStyle = {
36
overflow: 'hidden',
37
transition: 'all 0.3s'
38
};
39
40
const contentExpandedStyle = {
41
contentStyle,
42
padding: '4px 0',
43
border: '1px solid silver',
44
height: 'auto',
45
filter: 'opacity(1)'
46
};
47
48
const contentCollapsedStyle = {
49
contentStyle,
50
padding: '0 0',
51
border: '1px solid transparent',
52
height: '0',
53
filter: 'opacity(0)'
54
};
55
56
const ExpanderContext = React.createContext();
57
58
const Expander = ({children}) => {
59
const [expandedItem, setExpandedItem] = React.useState(null);
60
const expander = {
61
isExpandedItem: (title) => title === expandedItem,
62
setExpandedItem: (title) => {
63
setExpandedItem(expandedItem === title ? null : title);
64
}
65
};
66
return (
67
<ExpanderContext.Provider value={expander}>
68
<div style={expanderStyle}>
69
{children}
70
</div>
71
</ExpanderContext.Provider>
72
);
73
};
74
75
const Item = ({title, children}) => {
76
const expander = React.useContext(ExpanderContext);
77
const expanded = expander.isExpandedItem(title);
78
const handleHeaderClick = () => {
79
expander.setExpandedItem(title);
80
};
81
return (
82
<div style={itemStyle}>
83
<div style={headerStyle} onClick={handleHeaderClick}>
84
<div style={titleStyle}>{title}</div>
85
<div style={spacerStyle} />
86
<div style={iconStyle}>{expanded ? '△' : '▽'}</div>
87
</div>
88
<div style={expanded ? contentExpandedStyle : contentCollapsedStyle}>
89
{children}
90
</div>
91
</div>
92
);
93
};
94
95
96
// Usage example:
97
98
const App = () => {
99
return (
100
<div style={{width: '500px', height: '250px'}}>
101
<Expander>
102
<Item title="🍏🍌🍊 Fruits">
103
<ul>
104
<li>🍏 Apple</li>
105
<li>🍌 Banana</li>
106
<li>🍊 Orange</li>
107
</ul>
108
</Item>
109
<Item title="🥕🥒🍅 Vegetables">
110
<ul>
111
<li>🥕 Carrot</li>
112
<li>🥒 Cucumber</li>
113
<li>🍅 Tomato</li>
114
</ul>
115
</Item>
116
</Expander>
117
</div >
118
);
119
};
120
121
const root = document.querySelector('#root');
122
ReactDOM.render(<App/>, root );