I have built a custom tree view in React, and each item contains a dropdown which is positioned using Popper. Since the child elements are not visible on render, Popper is not positioning the dropdown correctly, for example:
When the tree is open on mount (i.e the children are visible), the positioning is correct:
Each level in the tree is rendered via a CategoryNavItem
component, which essentially looks like this:
<div className={ className.join(' ') }>
<div className={ `collection-nav_item-link depth${depth}` } style={{ paddingLeft: `${paddingLeft}px`}}>
<Link to={ linkTo } onClick={() => { setIsOpen(!isOpen) }}>
<i className="collection-nav_item-link_icon"></i>
<span className="collection-nav_item-link_text">{ category.name }</span>
</Link>
<Dropdown
toggleClassName="btn-icon-white btn-sm"
toggleContent={ <Icon name="ellipsis-h" />}
position="bottom-end"
size="small"
items={[
{ text: 'Edit category' },
{ text: 'Add subcategory', onClick: (() => { dispatch(openAddSubcategory(category)) }) }
]} />
</div>
{ children }
</div>
The Dropdown
component is where we use Popper, and it works well everywhere else. The visibility of a CategoryNavItem
is handled via the component's state in React.
Is there any way to trigger Popper's update()
method programmatically in React? We should force update
when toggling the item's visibility.
It turns out we just need to expose the update
property from the usePopper
hook, and then call it when setting the dropdown's visibility, for example:
const { styles, attributes, update } = usePopper(referenceElement, popperElement, {
placement: placement,
modifiers: [
{ name: 'arrow', options: { element: arrowElement } },
{ name: 'offset', options: { offset: [ 0, 3 ] } }
]
});
And similarly:
const toggleDropdown = (e) => {
e.preventDefault();
e.stopPropagation();
setVisible(!visible);
update();
};