React-select: Add ability to fit to text

Created on 20 Jul 2017  路  3Comments  路  Source: JedWatson/react-select

My case is trying to put react-select into Bootstrap's navbar:

<NavBar>
    <Nav pullRight>
        <Select... />
    </Nav>
</NavBar>

You can imagine what happens with this setup by looking here. Select gets shrunk and text is cut. I'd like to make it big enough to fit the text. I came up with the following workaround:

import 'react-select/dist/react-select.css';
import React from 'react';
import ReactDOM from 'react-dom';
import ReactSelect from 'react-select';
import measureText from 'measure-text';
import computedStyle from 'computed-style';
import zest from 'zest';

export default class Select extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            visible: false,
        };
    }

    getSelect() {
        return ReactDOM.findDOMNode(this.select);
    }

    getPlaceholder() {
        return zest('.Select-placeholder', this.getSelect())[0];
    }

    getInput() {
        return zest('.Select-input', this.getSelect())[0];
    }

    calcMaxTextWidth() {
        const placeholder = this.getPlaceholder();
        const fontFamily = computedStyle(placeholder, 'font-family');
        const fontSize = computedStyle(placeholder, 'font-size');
        const lineHeight = computedStyle(placeholder, 'line-height');
        const r = Math.max(this.props.options.map(o => measureText({
            text: o.label,
            fontFamily,
            fontSize,
            lineHeight,
        })['width']['value']));
        return Math.max(r, measureText({
            text: placeholder.textContent,
            fontFamily,
            fontSize,
            lineHeight,
        })['width']['value']);
    }

    render() {
        if ( ! this.maxTextWidth)
            setTimeout(() => {
                this.maxTextWidth = this.calcMaxTextWidth();
                this.getInput().style.minWidth
                    = parseFloat(computedStyle(this.getInput(), 'padding-left'))
                    + this.maxTextWidth
                    + parseFloat(computedStyle(this.getInput(), 'padding-right'))
                    + 'px';
                this.setState({
                    visible: true,
                });
            });
        return <ReactSelect searchable={false} clearable={false}
            style={{visibility: this.state.visible ? 'visible': 'hidden'}}
            ref={ref => this.select = ref}
            {...this.props} />;
    }
}

Which I don't like, and having this behaviour in react-select itself would be best. For that we can add fitToText prop. Or something along those lines.

Most helpful comment

Yes, even if I make parent bigger, I still need to calculate how much bigger. For that I need to measure width of all the text lines, find the longest and add react-select's "paddings." So, changing parent's width wouldn't make much difference.

Doing it from inside react-select must be simpler.

All 3 comments

Hi @x-yuri since react-select uses 100% width of the parent, it seems like the better approach would be to handle this on a parent of react-select instead of manipulating the style of the inner components. Was there a reason why you didn't go with this approach?

Yes, even if I make parent bigger, I still need to calculate how much bigger. For that I need to measure width of all the text lines, find the longest and add react-select's "paddings." So, changing parent's width wouldn't make much difference.

Doing it from inside react-select must be simpler.

Hello -

In an effort to sustain the react-select project going forward, we're closing old issues / pull requests.

We understand this might be inconvenient but in the best interest of supporting the broader community we have to direct our limited efforts to maintain the latest version.

If you feel this issue / pull request is still relevant and you'd like us to review it, please leave a comment and we'll do our best to get back to you.

Was this page helpful?
0 / 5 - 0 ratings