How can I imitate the look of the outline and label from Material-UI's outlined textfield?

前端 未结 3 715
误落风尘
误落风尘 2021-01-19 07:44

I\'m trying to imitate the outlined textfield from Material-UI but I don\'t know how to hide the border behind the title text.

In the below image, notice how the \"D

相关标签:
3条回答
  • 2021-01-19 08:09

    Just apply the same background color on the color div as the parent's background color, you can do it by background-color: inherit like this:

    <div style={inputContainerStyle}>
            <div style={{
              ...titleStyle,
              transform: 'translate(-43px, -11px) scale(0.75)',
              fontSize: '17px',
              color: 'rgba(0, 0, 0, 0.54)',
              position: 'absolute',
              background-color:'inherit' **(just add this line)**
            }}
            >
              Color
            </div>
            <div
              className="flex-row"
              style={{
                border: '1px solid rgba(0, 0, 0, 0.23)',
                padding: '18.5px 14px',
                borderRadius: '4px',
              }}
            >
              {
                availableColors.map(color => <div style={colorCircleStyle(color)} />)
              }
            </div>
          </div>
    
    0 讨论(0)
  • 2021-01-19 08:13

    UPDATE

    For many scenarios, my later answer (which avoids using TextField and therefore has no side-effects on FormControl context) may be more appropriate: How can I set an static outlined div similar to Material-UI's outlined textfield?


    There is a great deal of flexibility in what you can do with TextField. TextField supports plugging in different types of inputs (e.g. Select, input, custom pickers) via the inputComponent property. You could leverage this to put anything inside its labelled outline by creating a custom component like this OutlinedDiv:

    import React from "react";
    
    import TextField from "@material-ui/core/TextField";
    
    const InputComponent = ({ inputRef, ...other }) => <div {...other} />;
    const OutlinedDiv = ({ children, label }) => {
      return (
        <TextField
          variant="outlined"
          label={label}
          multiline
          InputLabelProps={{ shrink: true }}
          InputProps={{
            inputComponent: InputComponent
          }}
          inputProps={{ children: children }}
        />
      );
    };
    export default OutlinedDiv;
    

    The className passed to the inputComponent takes care of the CSS that makes this all work. You can then use this like in the following:

    import React from "react";
    import ReactDOM from "react-dom";
    
    import OutlinedDiv from "./OutlinedDiv";
    import Avatar from "@material-ui/core/Avatar";
    import deepOrange from "@material-ui/core/colors/deepOrange";
    import deepPurple from "@material-ui/core/colors/deepPurple";
    import red from "@material-ui/core/colors/red";
    import green from "@material-ui/core/colors/green";
    import blue from "@material-ui/core/colors/blue";
    import Grid from "@material-ui/core/Grid";
    
    function App() {
      return (
        <div className="App">
          <OutlinedDiv label="Color Picker">
            <Grid container justify="center" alignItems="center">
              <Avatar style={{ backgroundColor: deepOrange[500] }} />
              <Avatar style={{ backgroundColor: deepPurple[500] }} />
              <Avatar style={{ backgroundColor: red[500] }} />
              <Avatar style={{ backgroundColor: green[500] }} />
              <Avatar style={{ backgroundColor: blue[500] }} />
            </Grid>
          </OutlinedDiv>
          <br />
          <br />
          <OutlinedDiv label="Custom Outlined Thing">
            You can put whatever you want in here.
          </OutlinedDiv>
        </div>
      );
    }
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);
    

    0 讨论(0)
  • 2021-01-19 08:16

    The outlined textfield was really tricky to implement. When pushing that feature, we had to consider several options, each with their own drawbacks

    1. SVG Element

    Easy to build and animate, but tough to scale with the surrounding elements. If we had gone this route, we would have needed to listen for some type of resize event, which would mean either using a window resize event, which is not robust, or using a newer and less supported feature such as a ResizeObserver/MutationObserver. There are polyfills, but that would have increased the bundle size about 2K for a relatively small feature.

    The SVG route is likely what will be used in the future. It is also worth noting that this is how Google's Material Components Web solves the problem.

    1. Plain old border with a background on the label

    This is by far the simplest approach, but it is also somewhat inflexible. You can see an example of this in Google's new sign-in flow. There they actually set the background color to white. This is probably a fine approach for plenty of users, but of course won't work if your background is a gradient or some similar edge case. That said, there's no need to worry about resize because it's just a border.

    1. Fieldset and legend

    This is what we ended up going with, largely because of its flexibility for end users. Fieldset and its legend component are both built-in ways of attaining pretty much this exact functionality. The big drawbacks to this are that styling across browsers is tough, and the properties we'd be animating on are not performant, such as legend width. Additionally, it's always best to use semantic HTML of course, which this is not, which means we need to use aria-hidden to instruct screen readers to ignore the element.

    Depending on your goals, any one of these solutions may work best for you. Beware that getting the perfect solution that solves all of these problems may be very tricky!

    0 讨论(0)
提交回复
热议问题