Material-ui: The label value in outlined overlaps the border

Created on 14 Feb 2019  ·  20Comments  ·  Source: mui-org/material-ui

  • [x ] This is not a v0.x issue.
  • [x ] I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior 🤔

image

Current Behavior 😯

image

Steps to Reproduce 🕹

https://codesandbox.io/s/7m8vm8yxm6

Link:

1.
2.
3.
4.

Context 🔦

There are a lot of tabs that need to be display on and off,I'm not sure if it's my problem or bug

Your Environment 🌎

| Tech | Version |
|--------------|---------|
| Material-UI | 3.9.2|
| React | yes |
| Browser | |
| TypeScript | |
| etc. | |

TextField question

Most helpful comment

I had to explicitly set the label on the <Select> in addition to using the <InputLabel>

<FormControl variant="outlined">
  <InputLabel id="demo-simple-select-outlined-label">Age</InputLabel>
  <Select
    labelId="demo-simple-select-outlined-label"
    id="demo-simple-select-outlined"
    value=""
    onChange={() => {}}
    label="Age"    /* <==== Adding this fixed the issue for me */
  >
    <MenuItem value={10}>Ten</MenuItem>
    <MenuItem value={20}>Twenty</MenuItem>
    <MenuItem value={30}>Thirty</MenuItem>
  </Select>
</FormControl>

All 20 comments

@Andrew-Zn This is a visibility issue. We are measuring the label dimension to display the right gap. We have 3 class of solutions available:

  1. Remount the component every time it's displayed. For instance, this can be achieved with a key:
        <div className={this.state.flag ? classes.root : classes.hidden}>
          <TextField
+           key={this.state.flag}
            id="one"
            label="No.1"
            value="This is one" //这里是函数 如果有存在传入值。就是传入值的效果,还有默认效果
            fullWidth
            margin="normal"
            variant="outlined"
          />
        </div>
        <div className={!this.state.flag ? classes.root : classes.hidden}>
          <TextField
+           key={this.state.flag}
            id="two"
            label="No.2"
            value="This is two" //这里是函数 如果有存在传入值。就是传入值的效果,还有默认效果
            fullWidth
            margin="normal"
            variant="outlined"
          />
        </div>
  1. Use a background white color like Google is doing with it's official signin inputs:
import React, { Component } from "react";
import ReactDOM from "react-dom";
import { withStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField";
import Button from "@material-ui/core/Button";

import "./styles.css";

const styles = theme => ({
  root: {
    display: "flex",
    textAlign: "center",
    width: 300,
    marginLeft: 100,
    marginTop: 200
  },
  hidden: {
    display: "none"
  },
  button: {
    background: "green"
  },
+ label: {
+   backgroundColor: "white"
+  }
});

class App extends Component {
  state = {
    flag: true
  };
  handle = () => {
    this.setState({
      flag: !this.state.flag
    });
  };
  render() {
    const { classes } = this.props;
    return (
      <div className="App">
        <div className={this.state.flag ? classes.root : classes.hidden}>
          <TextField
+           InputLabelProps={{
+             classes: {
+               root: classes.label
+             }
+            }}
            id="one"
            label="No.1"
            value="This is one" //这里是函数 如果有存在传入值。就是传入值的效果,还有默认效果
            fullWidth
            margin="normal"
            variant="outlined"
          />
        </div>
        <div className={!this.state.flag ? classes.root : classes.hidden}>
          <TextField
+           InputLabelProps={{
+             classes: {
+               root: classes.label
+             }
+            }}
            id="two"
            label="No.2"
            value="This is two" //这里是函数 如果有存在传入值。就是传入值的效果,还有默认效果
            fullWidth
            margin="normal"
            variant="outlined"
          />
        </div>
        <Button className={classes.button} onClick={this.handle}>
          Change
        </Button>
      </div>
    );
  }
}
  1. Use the intersection Observer API internally, but requires a polyfill 👎

What do you think of 1.? It's probably good enough for now.

Thank you very much for your solutions. The second solution is most helpful for my question, so I take this suggestion. Thanks again. Best wishes!

Still same problem with material-ui 4.4.0.

Do you have a reproduction?

Here I have two Tabcontainer with one Textfield each. When changing the Tab, the label of the second Textfield still overlaps its border. First Textfield is working fine. Sorry for ugly code, but I have no beautifier on my phone... Hope it helps!

react: "^16.8.0"

material-ui: "^4.4.0"

import React from 'react';
import { TextField, Button, Typography, withStyles } from '@material-ui/core';

const styles = theme => ({

});

function TabContainer(props) {
  const { children, value, index, ...other } = props;

  return (
    <Typography
      component="div"
      role="tabpanel"
      hidden={value !== index}
      id={`full-width-tabpanel-${index}`}
      aria-labelledby={`full-width-tab-${index}`}
      {...other}
    >
      <div p={3} style={{ padding: '0px' }}>
        {children}
      </div>
    </Typography>
  );
}

class CheckoutPage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      openDrawer: false,
      name: '',
      street: '',
      value: 0,
    };
  }

  handleChange = index => {
    this.setState({ value: index, activeStep: index });
  };

  onChangeName = event => {
    this.setState({ name: event.target.value });
  };

  onChangeStreet = event => {
    this.setState({ street: event.target.value });
  };

  render() {
    const { theme } = this.props;
    const { name, street,  value } = this.state;

    return (
          <div>
            <TabContainer
              value={value}
              index={0}
              dir={theme.direction}
            >
              <TextField
                id="outlined-name"
                label="Vor- und Nachname"
                value={name}
                onChange={this.onChangeName}
                margin="normal"
                variant="outlined"
                fullWidth
                type="email"
                style={{ marginBottom: 20, marginTop: 20 }}
              />
              <div>
                <Button
                  variant="contained"
                  onClick={event => {this.handleChange(value + 1); }}>
                  Next
                </Button>
              </div>
            </TabContainer>
            <TabContainer
              value={value}
              index={1}
              dir={theme.direction}
            >
              <TextField
                id="street"
                label="Straße und Hausnr."
                value={street}
                onChange={this.onChangeStreet}
                variant="outlined"
                fullWidth
                style={{ marginBottom: 20, marginTop: 20 }}
              />

            </TabContainer>
      </div>
    );
  }
}
export default withStyles(styles, { withTheme: true })(CheckoutPage);

@kamami Thanks for sharing, at this point, the solution 3. in https://github.com/mui-org/material-ui/issues/16465#issuecomment-508080692 could be a great long term approach. Today, you could add a key={activeStep} prop on the TextField element. We could imagine the following fix tomorrow in the core:

diff --git a/packages/material-ui/src/TextField/TextField.js b/packages/material-ui/src/TextField/TextField.js
index a8f3cadaea..fe8e39103c 100644
--- a/packages/material-ui/src/TextField/TextField.js
+++ b/packages/material-ui/src/TextField/TextField.js
@@ -94,13 +94,14 @@ const TextField = React.forwardRef(function TextField(props, ref) {

   const [labelWidth, setLabelWidth] = React.useState(0);
   const labelRef = React.useRef(null);
+  // eslint-disable-next-line react-hooks/exhaustive-deps
   React.useEffect(() => {
     if (variant === 'outlined') {
       // #StrictMode ready
       const labelNode = ReactDOM.findDOMNode(labelRef.current);
       setLabelWidth(labelNode != null ? labelNode.offsetWidth : 0);
     }
-  }, [variant, required, label]);
+  });

   warning(

cc @eps1lon

@oliviertassinari This works fine.

Unfortunatly it breaks my autofocus method...
I added inputRef={el => { this.street = el; }}
to my textfield. My button triggers then this.street.focus(); This does not work, when I give Textfield the key={activeStep}.

@kamami Please open a separate issue. A codesandbox to reproduce the issue would help a lot.

Same issue in Vue's version of Material - https://github.com/vuetifyjs/vuetify/issues/7470

There is an good first issue open to update the logic to compute the label width at each render.

@oliviertassinari
Noticed this is closed, but i'm having this issue with 4.4.3 on a