score:1

Accepted answer

change accordion to:

class accordion extends react.component {
  render() {
    const { title, content, expand, onclick } = this.props;
    
    return (
      <div>
        <dt classname={expand ? 'title is-expanded' : 'title'} onclick={onclick}>
          {title}
        </dt>
        <dd classname={expand ? 'content is-expanded' : 'content'} onclick={onclick}>
          <p>{content}</p>
        </dd>
      </div>
    ); 
  }
}

and application to:

class application extends react.component {  
  // ...
  
  render() {
      const accordionlist = [{ title: 'first accordion', content: 'content 1' }, { title: 'second accordion', content: 'content 2' }, { title: 'third accordion', content: 'content 3' }];

      // ...

      <dl classname="accordion">
        {
          accordionlist.map((item, index) => (
            <accordion title={item.title} content={item.content} onclick={this.toggle(index + 1)} expand={this.state[`block${index+1}`]} />
          ))
        }
      </dl>

      // ...
}

update 1

i had another doubt. the number of blocks might not always be 3 then how can i dynamically set the block values (block1, block2 etc) to false in this.state and to expand in this.setstate?

all of the changes are required in application component. to make it work you need:

  • move accordionlist from render() to the state. i add id property to each element (and then use it inside map()). it makes sense to keep accordionlist in the state instead of render() function.
  • tweak toggle(id) and toggleexpand(expand) to use block id instead of array index.

class application extends react.component {  
  constructor (props) {
    super(props);
    this.state = {
      blocks: [
        { id: 1, title: 'first accordion', content: 'content 1', expanded: true },
        { id: 2, title: 'second accordion', content: 'content 2', expanded: false },
        { id: 3, title: 'third accordion', content: 'content 3', expanded: false },
        { id: 4, title: 'fourth accordion', content: 'content 4', expanded: false }
      ]
    };
  }
    
  toggle(id) {
    this.setstate((prevstate) => {
      const index = prevstate.blocks.findindex(item => item.id == id);
      prevstate.blocks[index].expanded = !prevstate.blocks[index].expanded;
      
      return { blocks: prevstate.blocks };
    });
  }
  
  toggleexpand(expand) {
    this.setstate((prevstate) => {
      const blocks = prevstate.blocks.map(item => {
        item.expanded = expand;
        return item;
      });
      
      return { blocks };
    });
  }
  
  render() {   
    return (
      <div classname="container">
        <h1>react accordion</h1>
        <button type="button" classname="btn" onclick={() => this.toggleexpand(true)}>expand all</button>
        <button type="button" classname="btn" onclick={() => this.toggleexpand(false)}>collapse all</button>
        <dl classname="accordion">
          {
            this.state.blocks.map(item => (
              <accordion key={item.id} title={item.title} content={item.content} expand={item.expanded} onclick={() => this.toggle(item.id)} />
            ))
          }
        </dl>
      </div>
    );
  }
}

class accordion extends react.component {
  render() {
    const { title, content, expand, onclick } = this.props;
    
    return (
      <div>
        <dt classname={expand ? 'title is-expanded' : 'title'} onclick={onclick}>
          {title}
        </dt>
        <dd classname={expand ? 'content is-expanded' : 'content'} onclick={onclick}>
          <p>{content}</p>
        </dd>
      </div>
    ); 
  }
}

reactdom.render(<application />, document.getelementbyid('app'));
@import url("https://fonts.googleapis.com/css?family=pt+sans");
html, body, #app {
  height: 100%;
}

.container {
  min-height: 100%;
  padding: 30px;
  font-family: 'pt sans';
  text-align: center;
}
.container h1 {
  text-align: center;
  color: #1569a8;
}
.container .btn {
  display: inline-block;
  margin-bottom: 20px;
  border: 1px solid #1569a8;
  background: white;
  color: #1569a8;
  padding: 5px 10px;
  border-radius: 5px;
  margin-right: 5px;
  font-size: 15px;
  cursor: pointer;
  outline: none;
}
.container .btn:hover {
  background: #1569a8;
  color: white;
  -webkit-transition: .5s;
  transition: .5s;
}

.accordion {
  margin: 0 auto;
  width: 80%;
}
.accordion .title {
  padding: 30px 30px;
  cursor: pointer;
  -webkit-transform: translate3d(0, 0, 0);
          transform: translate3d(0, 0, 0);
  color: white;
  position: relative;
  font-size: 20px;
  background: #1569a8;
  margin-bottom: -1px;
  border-bottom: 1px solid #0e4671;
  text-align: left;
}
.accordion .title::after {
  content: "+";
  font-size: 18px;
  color: white;
  -webkit-transition: -webkit-transform .5s ease-in-out;
  transition: -webkit-transform .5s ease-in-out;
  transition: transform .5s ease-in-out;
  transition: transform .5s ease-in-out, -webkit-transform .5s ease-in-out;
  position: absolute;
  right: 30px;
  font-family: monospace;
}
.accordion .title.is-expanded {
  -webkit-transition: background .5s;
  transition: background .5s;
  background: #0e4671;
}
.accordion .title.is-expanded::after {
  content: "-";
  -webkit-transform: rotate(-360deg);
          transform: rotate(-360deg);
}
.accordion .content {
  overflow: hidden;
  max-height: 0;
  -webkit-transition: max-height .5s;
  transition: max-height .5s;
  margin: 0;
  padding: 0 30px;
  border: solid 1px #eeeeee;
  border-top: 0;
  background: #e8f4fc;
}
.accordion .content p {
  padding: 30px 0;
  margin: 0;
  opacity: 0;
  -webkit-transition: .5s;
  transition: .5s;
}
.accordion .content.is-expanded {
  max-height: 500px;
  overflow: hidden;
}
.accordion .content.is-expanded p {
  opacity: 1;
}
.accordion:after {
  width: 100%;
  height: 10px;
  display: block;
  background: #0e4671;
  content: '';
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>


Related Query

More Query from same tag