Wrap a Custom React.js Component for an HTML Button
In this guide, we'll be taking a look at creating a custom component for an HTML button and extending its functionality other than attaching an event handler for its onClick attribute.
Oct 22, 2020 • 5 Minute Read
Introduction
React.js allows developers to extend the default functionality of an HTML input element by creating a component around it. This gives the input element more custom functionality, behavior, and even values that it can maintain on its own. In this guide, we'll be taking a look at creating a custom component for an HTML button and extending its functionality other than attaching an event handler for its onClick attribute.
Setup
Suppose that you want to create a button that does the following:
- Changes the color to red if it's unclickable
- Changes the color to green if it's clickable
- Changes the text of the button to "Loading..." if it's unclickable
This would be quite tedious if it were done manually. You'd probably have several JavaScript routines that would modify its behavior or several CSS files that might change how it looks depending on the classes added or removed by JavaScript. This is all good if you're doing it for a single button. However, if you expand to something like an array of buttons generated by a backend process, it tends to get messy to maintain.
To solve this, create a component representing that button, which you can call MyCustomButton:
import React from 'react';
export default class MyCustomButton extends React.Component {
constructor(props) {
this.state = {
text: "Click Me"
}
}
render() {
return (
<button>
{this.state.text}
</button>
);
}
}
Nothing special here. You start off by creating a component that maintains a text value in its state and renders the actual HTML button. The value of text becomes the actual text rendered for the button as called by this.state.text.
Changing Color to Red or Green
Next, you'd want to indicate if the button is clickable or not by changing its background color to red in the case of it being unclickable. This means that the disabled state of the button is set to true. When solving this type of problem in React.js, always remember to have everything managed by the component and just have values trigger the properties of that component via props, which is initially passed to the constructor. You can assume that props can have a property called disabled that can optionally be passed by an external component calling this MyCustomButton component. However, since it is optional, you want to have a default value for it. To do this, create a temporary variable called disabled that accesses this.props.disabled from within render():
var disabled = this.props.disabled || false;
The || indicates that if this.props.disabled is null, then it takes an initial value of false. Hook the value up to the actual disabled property of the HTML button:
<button disabled={disabled}>
{this.state.text}
</button>
Next, you can style the button by passing an object to its style attribute. Just like disabled, you can temporarily declare another variable to change the backgroundColor property of the object to red:
var style = { backgroundColor: 'red' };
However, if disabled is false, then the backgroundColor should be green:
if(disabled == false) {
style = { backgroundColor: 'green' }
}
Hook the variable style to the attribute style of the rendered HTML button:
<button disabled={disabled} style={style}>
{this.state.text}
</button>
Dealing with Text
To change the text of the button to "Loading...", you can use the same technique as in the previous section. Create a temporary variable text and set it to "Loading..." depending on the value of disabled:
var text = this.state.text;
if(disabled) {
text = "Loading...";
}
Replace the original rendered this.state.text to simply text within the jsx. Your rendered button should now look like the following:
<button disabled={disabled} style={style}>
{text}
</button>
Overall Code
Your overall code should now look like the following:
import React from 'react';
export default class MyCustomButton extends React.Component {
constructor(props) {
this.state = {
text: "Click Me"
}
}
render() {
var style = { backgroundColor: 'red' };
if(disabled == false) {
style = { backgroundColor: 'green' }
}
var text = this.state.text;
if(disabled) {
text = "Loading...";
}
return (
<button disabled={disabled} style={style}>
{text}
</button>
);
}
}
Conclusion
Instead of using a normal HTML button and having to maintain all sorts of behavior through external code, you can create a custom React.js component as a wrapper for that element with additional functionality. This is especially useful if you want to share common behavior for a dynamically generated set of UI components that are rendered by your app's own logic. Using React.js' passing of values to props, you can control the behavior of the custom component accordingly and even set default values for it so as not to burden external code to put in initial values.
As an extra step, try to see if you can make the "Click Me" text a default value if an external component fails to pass a value for the props property called buttonText (Hint: Is state a good place to store text in this scenario, or can you get away with simply using props)?