JSFiddle - React, Tailwind, and code Playground

JavaScript

function combinations(obj)
{
    var out = [];
    var meta = [], ml, cm;
    for(var p in obj) if(obj.hasOwnProperty(p))
    {
        if(Object.prototype.toString.call(obj[p]) != '[object Array]')
            obj[p] = [obj[p]];
        meta.push({prop: p, len: obj[p].length, current: 0});
    }
    function addNow()
    {
        var add = {};
        for(var i = 0, l = meta.length; i < l; i++)
            add[meta[i].prop] = obj[meta[i].prop][meta[i].current]
        out.push(add);
    }
    cm = ml = meta.length - 1;
    while(cm >= 0)
    {
        addNow();
        cm = ml;
        while(cm >= 0 && ++meta[cm].current >= meta[cm].len)
        {
            meta[cm].current = 0;
            cm--;
        }
    }
    return out;
}

append('In my shop there is:');
combinations({
    color: ['red', 'green', 'blue'],
    type: ['hat', 'tie'],
    price: '$39'
}).forEach(function(e){ console.log(e); append('    A '+e.color+' '+e.type+' that costs '+e.price); });

function append(t){document.body.appendChild(document.createElement('div')).innerText=t}