JSFiddle - React, Tailwind, and code Playground

by matt_friedman

HTML

<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.1/knockout-min.js"></script>
<div data-bind="foreach:groups" id="menu">
    <div class="header" data-bind="text:name, accordion: openState, click: toggle">&nbsp;</div>
    <div class="items" data-bind="foreach:items">
        <div data-bind="text:name">&nbsp;</div>
    </div>
</div>

CSS

#menu {
            width: 400px;
            cursor: pointer;
        }

        .header {
            background-color: #a2a2a2;
        }

        .items {
            background-color: #c5c5c5;
        }

JavaScript

ko.bindingHandlers.accordion = {

        init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
            $(element).next().hide();
        },
        update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {

            var slideUpTime = 300;
            var slideDownTime = 400;

            var openState = ko.utils.unwrapObservable(valueAccessor());
            var focussed = openState.focussed;
            var shouldOpen = openState.shouldOpen;

            if (focussed) {

                var clickedGroup = viewModel;

                $.each(bindingContext.$root.groups(), function (idx, group) {
                    if (clickedGroup != group) {
                        group.openState({focussed: false, shouldOpen: false});
                    }
                });
            }

            var dropDown = $(element).next();

            if (focussed && shouldOpen) {
                dropDown.slideDown(slideDownTime);
            } else if (focussed && !shouldOpen) {
                dropDown.slideUp(slideUpTime);
            } else if (!focussed && !shouldOpen) {
                dropDown.slideUp(slideUpTime);
            }
        }
    };

    function ViewModel() {

        var self = this;
        self.groups = ko.observableArray([]);

        function Group(id, name) {

            var self = this;
            self.id = id;
            self.name = name;

            self.openState = ko.observable({focussed: false, shouldOpen: false});

            self.items = ko.observableArray([]);

            self.toggle = function (group, event) {
                var shouldOpen = group.openState().shouldOpen;
                self.openState({focussed: true, shouldOpen: !shouldOpen});
            }
        }

        function Item(id, name) {
            var self = this;
            self.id = id;
            self.name = name;
        }

        var g1 = new Group(1, "Group 1");
        var g2 = new...