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.
Suppose that you want to create a button that does the following:
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
:
1import React from 'react';
2
3export default class MyCustomButton extends React.Component {
4 constructor(props) {
5 this.state = {
6 text: "Click Me"
7 }
8 }
9
10 render() {
11 return (
12 <button>
13 {this.state.text}
14 </button>
15 );
16 }
17}
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
.
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()
:
1var 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:
1<button disabled={disabled}>
2 {this.state.text}
3</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
:
1var style = { backgroundColor: 'red' };
However, if disabled
is false
, then the backgroundColor
should be green:
1if(disabled == false) {
2 style = { backgroundColor: 'green' }
3}
Hook the variable style
to the attribute style
of the rendered HTML button:
1<button disabled={disabled} style={style}>
2 {this.state.text}
3</button>
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
:
1var text = this.state.text;
2
3if(disabled) {
4 text = "Loading...";
5}
Replace the original rendered this.state.text
to simply text
within the jsx
. Your rendered button should now look like the following:
1<button disabled={disabled} style={style}>
2 {text}
3</button>
Your overall code should now look like the following:
1import React from 'react';
2
3export default class MyCustomButton extends React.Component {
4 constructor(props) {
5 this.state = {
6 text: "Click Me"
7 }
8 }
9
10 render() {
11 var style = { backgroundColor: 'red' };
12
13 if(disabled == false) {
14 style = { backgroundColor: 'green' }
15 }
16
17 var text = this.state.text;
18
19 if(disabled) {
20 text = "Loading...";
21 }
22
23 return (
24 <button disabled={disabled} style={style}>
25 {text}
26 </button>
27 );
28 }
29}
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
)?