Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Bootstrap - Best practice for a conditional OverlayTrigger

We have a button that we want to have enabled or disabled depending on some condition. Furthermore, we want the hover effect of the button when disabled to display a tooltip explaining why it is disabled.

Currently, we have something like this:

export class NextButton extends React.Component {
    makePopover () {
        return (
            this.props.someCondition && <Popover>Please enter a title.</Popover>
        )
    }

    render () {
        return (
            <div>
                <OverlayTrigger placement='top' overlay={this.makePopover()}>
                    {/* wrap this in a div so when the button is disabled, the popover still works */}
                    <div>
                        <Button
                            onClick={() => this.props.goToNextPage()}
                            disabled={this.props.someCondition}
                        >
                            Next
                        </Button>
                    </div>
                </OverlayTrigger>
            </div>
        );
    }
}

Now, if we look closely at the makePopover function, if someCondition is false, Popover will not be rendered and OverlayTrigger throws an error if anything without an id is returned.

Therefore, to fix this we tried:

this.props.someCondition ? <Popover>...</Popover> : <span>...</span>

This helped but displayed other warnings:

Warning: Unknown props placement, arrowOffsetLeft, arrowOffsetTop, positionLeft, positionTop on tag. Remove these props from the element.

Now, instead of conditionally displaying the Popover, we could wrap the conditional around the entire OverlayTrigger itself, doing something like:

this.props.someCondition
?
    <OverlayTrigger>
        <Button>Next</Button>
    </OverlayTrigger>
:
<Button>Next</Button>

What is the best practice for how to deal with conditional tooltips? Any help would be greatly appreciated.

like image 422
noblerare Avatar asked Aug 28 '26 17:08

noblerare


2 Answers

I was facing the same problem I thought the cleanest way to solve it is to use a conditional wrapper.

const ConditionalWrapper = ({
    condition,
    wrapper,
    children,
}) => (condition ? wrapper(children) : children);


export class NextButton extends React.Component {
    render () {
        return (
            <div>
                <ConditionalWrapper
                    condition={this.props.someCondition}
                    wrapper={children => (
                        <OverlayTrigger
                            overlay={<Popover>Please enter a title.</Popover>}
                            placement='top'
                        >
                            {children}
                        </OverlayTrigger>
                        )}
                >
                    {/* wrap this in a div so when the button is disabled, the popover still works */}
                    <div>
                        <Button
                            onClick={() => this.props.goToNextPage()}
                            disabled={this.props.someCondition}
                        >
                            Next
                        </Button>
                    </div>
                </ConditionalWrapper>
            </div>
        );
    }
}
like image 141
Alexus Avatar answered Aug 30 '26 10:08

Alexus


Here is Alexus answer in Typescript (mostly):

interface IConditionalWrapperProps {
    condition: boolean;
    wrapper: (children: React.ReactNode) => JSX.Element;
    children: JSX.Element;
}

const ConditionalWrapper = ({
    condition,
    wrapper,
    children,
}: React.PropsWithChildren<IConditionalWrapperProps>) => (condition ? wrapper(children) : children);

export class NextButton extends React.Component {
render () {
    return (
        <div>
            <ConditionalWrapper
                condition={this.props.someCondition}
                wrapper={children => (
                    <OverlayTrigger
                        overlay={<Popover>Please enter a title.</Popover>}
                        placement='top'
                    >
                        {children}
                    </OverlayTrigger>
                    )}
            >
                {/* wrap this in a div so when the button is disabled, the popover still works */}
                <div>
                    <Button
                        onClick={() => this.props.goToNextPage()}
                        disabled={this.props.someCondition}
                    >
                        Next
                    </Button>
                </div>
            </ConditionalWrapper>
        </div>
    );
}
like image 39
stephen Avatar answered Aug 30 '26 08:08

stephen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!