<div id="container">
    <!-- This element's contents will be replaced with your component. -->
</div>
body {
    padding: 5px
    
}
/* Controllers Hierarchy
  App
    C SearchBar
    f ProductTable
      f CategoryRow
      f ProductRow
*/

function ProductRow(props) {
  
  let styles = {border: 'dotted red 1px', paddingLeft: '8px', color: 'blue'}

  if(!props.stocked){
    styles.color= 'red'
    styles.fontStyle = 'italic'
    styles.fontFamily = 'normal'; 
  }         
  return <div style={styles}>   {props.name}  {props.price}  </div>;
}

function CategoryRow(props){
  return <div style={{background: 'yellow', paddingLeft: '4px'}} >  {props.category} </div>;
}

function ProductTable(props)  {
  let rows = [];
  let lastCategory = null;

  const products = props.products
  .filter( p => {        
    const key = props.searchBoxKey.toLowerCase();
    const index = p.name.toLowerCase().indexOf(key);
    return (index >= 0 )
  });

  products.forEach( (x, i) => {  
    if(x.category !== lastCategory){
      rows.push( <CategoryRow category={x.category}  key={'a' + i }  />); 
      lastCategory = x.category;
    }
    rows.push( <ProductRow 
                 name={x.name} 
                 price={x.price} 
                 stocked={x.stocked} 
                 key={'b'+ i }
            /> ) 
  });

  return <div style={{border: 'solid green'}} >   {rows}    </div>;        
}


class SearchBar extends React.Component{
  constructor(props){
    super(props);
    this.handleFilterTextChange = this.handleFilterTextChange.bind(this);  
  };
  
  handleFilterTextChange(e){
    this.props.handleSearchBox(e.target.value)
  };

  render(){  
    return (
      <form>
        <input 
          type="text"
          placeholder="Search..."
          onChange={this.handleFilterTextChange}
         />
        <p>
          <input type="checkbox" /> {' '} Only show products in stock 
        </p>  
      </form>);
  };
}
class App extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      searchBoxKey: '',
      checkShowInStock: false
    };
    this.handleSearchBox = this.handleSearchBox.bind(this);
  }

  handleSearchBox(filterText){
      this.setState({
        searchBoxKey : filterText
      });
   }  

  render(){ 
    return (
      <div key='i1'>
        
       <SearchBar 
         handleSearchBox={this.handleSearchBox}
       />
        
       <ProductTable 
         products={this.props.products} 
         searchBoxKey={this.state.searchBoxKey} 
         key='i2'
       /> 
        
     </div>);
    };
};

const PRODUCTS = [
  { category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football'},
  { category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball'},
  { category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball'},
  { category: 'Sporting Goods', price: '$79.99', stocked: true, name: 'Socer'},
  { category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch'},
  { category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5'},
  { category: 'Electronics', price: '$299.99', stocked: false, name: 'BacoPhone 7'},
  { category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7'}
];
 
ReactDOM.render(
  <App products={PRODUCTS} />
  , document.getElementById('container')
);

View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://unpkg.com/react/umd/react.development.js
  2. https://unpkg.com/react-dom/umd/react-dom.development.js