JSFiddle - React, Tailwind, and code Playground

HTML

stdin(mergeExtend(theme, ['ANDROID'], ['IOS']));

JavaScript

var theme = {
    Form: {
        LabelTop: {
            backgroundColor: 'red',
            fieldBorderColor: '#cacacf',
            rowHeight: 40,
            hintText: {
                font: {
                    fontSize: 12
                },
                colorOn: '#3accf1',
                colorOff: '#cacacf',
                ANDROID: {
                    width: 200
                }
            },

        }
    },
    Modal: {
        id: 'md',
        backgroundColor: '#fff',
        IOS: {
            color: 'red'
        }
    }
};

function mergeExtend(obj, merge, skip) {
    var o, o1, nObj = {};
    for (o in obj) {
        // ensure we are only checking this obj's keys
        if (obj.hasOwnProperty(o)) {
            // check if we have keys to merge
            if ((merge || []).indexOf(o) > -1) {
                // if something was defined in merge, we expect the value to be an object
                for (var o1 in obj[o]) {
                    if (obj[o].hasOwnProperty(o1)) {
                        // put child obj val under parent key
                        nObj[o1] = obj[o][o1];
                    }
                }
                // ensure we are not skipping this key
            } else if ((skip || []).indexOf(o) === -1) {
                if (typeof obj[o] === 'object') {
                    // go recursive if we are not merging and val is an object
                    nObj[o] = mergeExtend(obj[o], merge, skip);
                } else {
                    // otherwise just copy the key val over
                    nObj[o] = obj[o];
                }
            }
        }
    } 
    
    return nObj;
}

console.log(mergeExtend(theme, ['ANDROID'], ['IOS']));