JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://rawgit.com/SteveSanderson/knockout.mapping/master/build/output/knockout.mapping-latest.js"></script>
<div>
   <div data-bind="foreach: cartItems">
     <div>
        <select data-bind="options: $parent.getProducts(),
                          optionsText: function (item) { return $parent.getProductName(item); },
                          optionsValue: function (item) { return $parent.getProductValue(item); }, 
                          optionsCaption: 'Choose a product',
                          value: cartItemName"
        >
        </select>
     </div>
     <div>
       <select data-bind="options: $parent.getProductColours(cartItemName),
                          optionsText: $data,
                          optionsCaption: 'Choose a colour',
                          value: cartItemColour,
                          visible: cartItemName() != undefined"
       >
       </select>
     </div>
</div>
      <div>
        <button data-bind="text: 'add cart item', click: addCartItem" />
        <button data-bind="text: 'empty cart', click: emptyCart" />
        <button data-bind="text: 'save cart', click: saveCart" />
        <button data-bind="text: 'load cart', click: loadCart" />
      </div>
    </div>

JavaScript

var cartItemsAsJson = "";
var handlerVM = function () {
  var self = this;
  self.cartItems = ko.observableArray([]);
  self.availableProducts = ko.observableArray([]);
  self.language = ko.observable();
  self.init = function () {
    self.initProducts();
    self.language("english");
  }
  self.initProducts = function () {
    self.availableProducts.push(
      new productVM("Shelf", ['White', 'Brown']),
      new productVM("Door", ['Green', 'Blue', 'Pink']),
      new productVM("Window", ['Red', 'Orange'])
    );
  }
  self.getProducts = function () {
    return self.availableProducts;
  }
  self.getProductName = function (product) {
    if (product) {
      return self.language() == "english" ? 
        product.productName().english : product.productName().french;
    }
  }
  self.getProductValue = function (selectedProduct) {
    // if not caption
    if (selectedProduct) {
      var matched = ko.utils.arrayFirst(self.availableProducts(), function (product) {
        return product.productName().english == selectedProduct.productName().english;
      });
      return matched;
    }
  }
  self.getProductColours = function (selectedProduct) {
    selectedProduct = selectedProduct();
    if (selectedProduct) {
      return selectedProduct.availableColours();
    }
  }
  self.addCartItem = function () {
    self.cartItems.push(new cartItemVM());
  }
  self.emptyCart = function () {
    self.cartItems([]);
  }
  self.saveCart = function () {
    cartItemsAsJson = ko.toJSON(self.cartItems);
    console.log(cartItemsAsJson);
  }
  self.loadCart = function () {
    var loadedCartItems = ko.mapping.fromJSON(cartItemsAsJson, {
      create: function(options) {
        return new cartItemVM(options.data);
      }
    });
    
    loadedCartItems().forEach(
    	ci => {
		    // Match item to products
				const firstSelection = ci.cartItemName().productName;
        ci.cartItemName(
        	self.availableProducts()
          	.find(p => p.productName().english ===...