In this article we will look at how we can implement Material Design's popular floating input labels with React.
It's a fun little exercise and it's not actually too difficult.
If you'd like to skip ahead, feel free to check out the CodeSandbox.
To make floating labels work, we need to work with three elements:
<input>
element<label>
<div>
When the input is empty, the label will float over the actual text input, exactly in the same position where any user input would appear.
When the text input has a value, we will move the label up and out of the way while also scaling it down a bit.
Keeping in mind the two distinct states (filled vs. empty) and our three elements, we can go ahead and implement the React part of our component:
function TextField({ id, label, style, value, onChange, ...rest }) {const isEmpty = String(value || '').length === 0const isFilled = !isEmptyreturn (<divclassName={['TextField',isEmpty ? 'TextField--isEmpty' : '',isFilled ? 'TextField--isFilled' : ''].join(' ')}style={style}><label className="TextField-label" htmlFor={id}>{label}</label><input{...rest}className="TextField-input"id={id}value={value}onChange={onChange}/></div>)}export default TextField
To keep things simple, we're assuming our component is always controlled (not optionally uncontrolled).
When implementing the CSS for the Material Design floating labels, pay special attention that the label's text is aligned exactly with the input's text.
Especially getting this to work across browsers is a bit tricky, but I've left some tips in the comments below:
.TextField {position: relative;line-height: 0;}.TextField-label {position: absolute;font: inherit;transition: transform 200ms;transform-origin: top left;color: gray;pointer-events: none;line-height: 1;display: block;}.TextField--isFilled .TextField-label {transform: translate(0, -1em) scale(0.8);}.TextField--isEmpty .TextField-label {transform: translate(0, 0.5em) scale(1);}.TextField-input {/* 💡 Make sure that the input's text styles are the same as the label's: */font: inherit;/* 💡 Setting 'box-sizing: content-box;' really helps makingthe height of the input predictable and consistent acrossbrowsers: */box-sizing: content-box;height: 2em;line-height: 1;margin: 0;padding: 0;border: none;border-bottom: 2px solid gray;outline: none;width: 100%;}
To test the text alignment of the label with the input, it can help to disable the styling for the filled state:
/* .TextField--isEmpty */ .TextField-label {transform: translate(0, 0.5em) scale(1);opacity: 0.5;}/*.TextField--isFilled .TextField-label {transform: translate(0, -1em) scale(0.8);}*/
That's the basics of implementing Material Design's floating labels with React.
Thank you for reading, I hope this article was helpful to you.
Check out the CodeSandbox for the complete implementation.
Hi, I’m Max! I'm a fullstack JavaScript developer living in Berlin.
When I’m not working on one of my personal projects, writing blog posts or making YouTube videos, I help my clients bring their ideas to life as a freelance web developer.
If you need help on a project, please reach out and let's work together.
To stay updated with new blog posts, follow me on Twitter or subscribe to my RSS feed.