Reputation: 1951
By default, the reactstrap collapse component always collapses vertically. How can I make it collapse horizontally?
Maybe I'm missing something... https://reactstrap.github.io/components/collapse/
Upvotes: 3
Views: 4610
Reputation: 1951
So, I created a Component that can collapse both ways, horizontally or vertically. Vertically collapsing is still in test, but it will work for horizontal collapsing.
export default class Collapse extends Component {
static props = {
isOpen: PropTypes.bool.isRequired,
vertical: PropTypes.bool,
elementMaxLength: PropTypes.string,
onOpen: PropTypes.func,
onClose: PropTypes.func,
}
static defaultProps = {
vertical: false,
elementMaxLength: '300px',
onOpen: () => console.log('Opened'),
onClose: () => console.log('Closed'),
}
constructor(props) {
super(props);
this.state = {
cssTarget: '_collapseH'
}
}
componentDidMount() {
if (this.props.vertical)
this.setState({cssTarget: '_collapseV'})
if (this.props.isOpen)
this.collapse();
}
componentDidUpdate(prevProps, prevState, snapshot) {
if (prevProps.isOpen !== this.props.isOpen)
this.collapse();
}
collapse() {
var content = this.refs.collapseDiv;
if (content)
if (this.decide(content))
this.close(content)
else
this.open(content)
}
decide(content) {
if (this.props.vertical)
return content.style.maxHeight;
return content.style.maxWidth;
}
open(content) {
this.assign(content, this.props.elementMaxLength);
this.props.onOpen();
}
close(content) {
this.assign(content, null)
this.props.onClose();
}
assign(content, value) {
if (this.props.vertical)
content.style.maxHeight = value;
else
content.style.maxWidth = value;
}
render() {
return (
<div ref='collapseDiv' target={this.state.cssTarget}>
{this.props.children}
</div>
);
}
}
So basically we render a DIV with a reference to it so that we can access it inside our component with this.refs
. And we render all children passed to this component inside this DIV.
To control if we should expand or collapse, we have the prop isOpen, that changes from TRUE to FALSE through this.setState
inside our parent component.
When we use this.setState
inside our parent it will trigger a re-rendering for our parent, also triggering a re-rendering the Collapse component. Which will also trigger
componentDidUpdate
where we will start the animation.
To control the animation I used CSS:
div[target='_collapseV'] {
display: flex;
flex: 1;
overflow: hidden;
background-color: maroon;
max-height: 0;
transition: max-height 1s ease-out;
}
div[target='_collapseH'] {
display: flex;
flex: 1;
overflow: hidden;
background-color: maroon;
max-width: 0;
transition: max-width 1s ease;
}
The target attribute is set in the same DIV that we set the ref
attribute. If the prop
vertical
is set to true, then our target att will change to _collapseV
making the component collapse vertically.
To trigger the animation we change the value of max-width
or max-height
inside the assign
function, which is called inside componentDidUpdate
.
The only downside is that you must know the max length (width or height) of the content
being rendered inside this component, and set in the prop elementMaxLength
. It doesn't have to be the same value, but elementMaxLength should be bigger than the content length.
And thats it.
I really don't know if this is the best way to go and I'm certain that there is a lot of room for improvements. But I think was a good solution, works fine and you don't have to install any packages.
As I said before vertically collapsing still needs some testing, but the point was to create something that collapses horizontally.
Upvotes: 3