Build a Fancy Focus Text Box using ReactJS and LESS CSS
Today, I'm going to talk about how to create a focus text box control using React JS and LESS CSS. The class should replace inputs of type text and password, and provide some relatively fancy feedback to the user as to which input is focused. I'm going to assume you're at least halfway familiar with these tools, but if you're not, I suggest you take a look using the links above. If you're just interested in an example, you can take a look here.
I'm going to split the article up into two sections. First, I'll go over the React stuff and how I'm breaking up the classes and what each of the classes do and so on. Next, we'll discuss how the CSS is used to create the fancy animations to indicate that the text box has been focused.
React
I've got two classes for the React section. The App
class is used solely as a container for holding the application, while the FocusBox
class is used to render the focus input text box.
var App = React.createClass({
render: function() {
return <div>
<FocusBox placeholder="Text..." />
<FocusBox placeholder="Error!" error="true" />
</div>;
}
});
var FocusBox = React.createClass({
getInitialState: function() {
return {
focused: false
};
},
focus: function() {
this.setState({ focused: true });
},
blur: function() {
this.setState({ focused: false });
},
render: function() {
return <div className={"focus-box" + (this.state.focused ? " focus" : "") + (this.props.error ? " error" : "")}>
<div>
<input type={this.props.type || "text"} placeholder={this.props.placeholder} onFocus={this.focus} onBlur={this.blur} />
<div className="focus">
<div></div>
</div>
</div>
</div>;
}
});
The App
class is pretty self-explanatory, so there's not really much to say there. For the FocusBox
class, we're setting our initial state to just have the focused property set to false. This is what we're using to keep track of when the user focuses on the text box. Related to that are the two other non-render functions: focus and blur, which are hooked up to the appropriate events on the input field in the render method. When the user focuses on the text box, the focused state property is updated to true to reflect that, and set to false when the user blurs (focuses on something else) on the text box.
The render method is used to build what the user sees when we add a FocusBox
to a parent. The className
property of the containing div has a couple of conditionals that provide custom styling. The first is the focus class, which adds the highlight colour when the focus state property is set. The second is for an error condition, which changes the highlight colour to red.
LESS CSS
Note: There are a few mixins in the LESS CSS below that aren't defined. They're almost exclusively used to hide ugly vendor prefixes. For the full LESS code, take a look at the source of the demo page.
div.focus-box {
float:left;
display:block;
width:250px;
border:solid 1px #AAA;
margin-right:15px;
margin-top:10px;
div {
float:left;
width:100%;
text-align:inherit;
>input {
float:left;
width:100%;
-webkit-appearance:none;
text-align:inherit;
padding:@spacing;
border:none;
font-size:0.875em;
background:white;
outline:none;
.border-box;
.border-radius;
.transition(background ease 250ms);
}
>div.focus {
float:left;
width:100%;
margin-top:-1px;
position:relative;
height:1px;
background:transparent;
border-color:transparent;
>div {
position:absolute;
z-index:2;
width:100%;
.transform(scale(0, 1));
height:2px;
margin-top:-1px;
background:@select-colour;
.transition(all ease 250ms);
}
}
}
&.focus {
input { background:#DEE9FA !important; }
div.focus>div { .transform(scale(1, 1)) !important; }
}
&.error {
div.focus>div { background:red !important; }
}
&.focus.error {
input { background:rgba(255, 0, 0, 0.125) !important; }
}
}
For positioning, we're moving the focus bar up a pixel so as to cover up the lower border on the text box. There are two animations that are occurring when a text box gains focus: first, we're spreading the focus bar across the bottom of the input, and second, we're fading the background of the input to a blue (or red, if errored). The first is accomplished using the transform:scale rule. Transforming the scale to (0, 1) indicates that the width of the element should be rendered as zero, while the height should be 100%, which is our default. When focusing, the scale changes to (1, 1), which indicates the width should jump back up to 100%. It's animated because we've got a transition set for the transform property. The background fade is accomplished in much the same manner, adding a transition to the background property of the input element.
Conclusion
And that's it! As I mentioned above, I've put together a demo page which shows off the text box in its final form. You can see it here. Thanks for reading!