JSFiddle - React, Tailwind, and code Playground
HTML
Header Text: <input data-bind="value: header" />
Group count: <input data-bind="value: count" />
<div data-bind="foreachGrouped: { data: items, count: count }">
<h1 data-bind="html: $root.header"></h1>
<ul data-bind="foreach: $data">
<li data-bind="text: $data"></li>
</ul>
</div>
CSS
ul { background-color: #aaa; }
li { display: inline-block; }
JavaScript
ko.bindingHandlers.foreachGrouped = {
init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var groupedItems,
options = valueAccessor();
//create our own computed that transforms the flat array into rows/columns
groupedItems = ko.computed({
read: function() {
var index, length, group,
result = [],
count = +ko.utils.unwrapObservable(options.count) || 1,
items = ko.utils.unwrapObservable(options.data);
//create an array of arrays (rows/columns)
for (index = 0, length = items.length; index < length; index++) {
if (index % count === 0) {
group = [];
result.push(group);
}
group.push(items[index]);
}
return result;
},
disposeWhenNodeIsRemoved: element
});
//use the normal foreach binding with our new computed
ko.applyBindingsToNode(element, { foreach: groupedItems }, bindingContext);
//make sure that the children of this element are not bound
return { controlsDescendantBindings: true };
}
};
ko.applyBindings({
header: ko.observable("Group Header"),
items: ko.observableArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
count: ko.observable(4)
});