2

I have the following structure in HTML/JSX

<ul>
  <li className="active">Tab 1</li>
  <li>Tab 2</li>
  <li>Tab 3</li>
</ul>

I want to add class name "active" on the <li> element I click on. For example: clicking on tab 2 should remove class "active" from tab1 and add it to tab2.

Pasting my react code here for better understanding.

import React, {
    Component
} from 'react';

export default class Tab extends Component {
  constructor(props){
   super(props);
   this.changeTab = this.changeTab.bind(this);
  }
  changeTab(){
    // solution here
  }
  render() {
    return (
        <div>
            <ul>
                <li onClick={this.changeTab}>Tab 1</li>
                <li onClick={this.changeTab}>Tab 2</li>
                <li onClick={this.changeTab}>Tab 3</li>
            </ul>
        </div>
    );
  }
}

How to achieve this functionality using the React way? I don't want to use any other external library.TIA.

3 Answers 3

1

You can store active tab index in the component state and change it after click on tab. Look at this working example, it explains the general principle of tabs behaviour with React.js - https://jsfiddle.net/t9ss04jL/

  class HelloWidget extends React.Component{
    constructor(props) {
      super(props);

      this.state = {
        activeTabIndex: 0
      };
    }

    changeTab(newActiveTabIndex) {
      this.setState({
        activeTabIndex: newActiveTabIndex
      });
    }

    render() {
            const { activeTabIndex } = this.state;

        return (
            <div>
              <ul>
                  <li
                    className={activeTabIndex === 0 ? 'active' : ''}
                    onClick={this.changeTab.bind(this, 0)}
                  >
                    Tab 1
                  </li>
                  <li
                    className={activeTabIndex === 1 ? 'active' : ''}
                    onClick={this.changeTab.bind(this, 1)}
                  >
                    Tab 2
                  </li>
                  <li
                    className={activeTabIndex === 2 ? 'active' : ''}
                    onClick={this.changeTab.bind(this, 2)}
                  >
                    Tab 3
                  </li>
              </ul>
          </div>
        )
    }
  }

  React.render(<HelloWidget />, document.getElementById('container'));
Sign up to request clarification or add additional context in comments.

Comments

0

You have the state of the component available for your usage, and since you are calling the methods from within the component itself, you do not need to bind them in your constructor. Here is the solution using function generation :

import React, { Component } from 'react';

export default class Tab extends Component {
    constructor(props){
        super(props);
        this.state = { tabActive: 1 };
    }

    /**
     * Function generator to handle switching tab with tabIndex
     * 
     * @param {number} tabIndex 
     * @returns {function}
     * @memberof Tab
     */
    changeTab(tabIndex) {
        return () => {
            this.setState({ tabActive: tabIndex });
        };
    }

    /**
     * determines the class name based on the active tab
     * 
     * @param {number} tabIndex 
     * @returns {string}
     * @memberof Tab
     */
    getClassName(tabIndex) {
        return (this.state.tabActive === tabIndex ? 'active' : '');
    }

    render() {
        return (
            <div>
                <ul>
                    <li className={ this.getClassName(1) }
                        onClick={ this.changeTab(1) }>
                        Tab 1
                    </li>
                    <li className={ this.getClassName(2) }
                        onClick={ this.changeTab(2) }>
                        Tab 2
                    </li>
                    <li className={ this.getClassName(3) }
                        onClick={ this.changeTab(3) }>
                        Tab 3
                    </li>
                </ul>
            </div>
        );
    }
}

Comments

0

React is all about components. In that case, I suggest you to create specific and reusable components such as Tab and TabBar. The good thing about it is that your code get's cleaner and easier to understand. You only have to use state to keep track of the current tab.

const Tab = ({ active, children, onClick }) => 
  <li className={active ? 'active' : ''} onClick={onClick}>{children}</li>

class TabBar extends React.Component {
  constructor() {
    super()
    
    this.state = { activeTabIndex: 0 }
    
    this.changeTab = this.changeTab.bind(this)
  }
  
  changeTab(index) {
    this.setState({ activeTabIndex: index })
  }

  render() {
    const { activeTabIndex } = this.state
    
    return (
      <div>
        <ul>
          <Tab active={activeTabIndex === 0} onClick={this.changeTab.bind(this, 0)}>Tab 1</Tab>
          <Tab active={activeTabIndex === 1} onClick={this.changeTab.bind(this, 1)}>Tab 2</Tab>
          <Tab active={activeTabIndex === 2} onClick={this.changeTab.bind(this, 2)}>Tab 3</Tab>
        </ul>
      </div>
    )
  }
}

ReactDOM.render(<TabBar />, document.getElementById('root'))
#root li {
 display: inline-block;
 margin: 0 10px;
}

#root li.active {
  background-color: red;
  color: white;
  font-weight: bold;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="root"></div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.