querySelector search immediate children

You can't. There's no selector that will simulate your starting point.

The way jQuery does it (more because of a way that qsa behaves that is not to their liking), is that they check to see if elem has an ID, and if not, they temporarily add an ID, then create a full selector string.

Basically you'd do:

var sel = '> someselector';
var hadId = true;
if( !elem.id ) {
    hadID = false;
    elem.id = 'some_unique_value';
}

sel = '#' + elem.id + sel;

var result = document.querySelectorAll( sel );

if( !hadId ) {
    elem.id = '';
}

This certainly isn't jQuery code, but from what I remember, it is basically what they do. Not just in this situation, but in any situation where you're running a selector from the context of a nested element.

Source code for Sizzle


Though it's not a full answer, you should keep an eye on the W3C Selector API v.2 which is already available in most browser, both desktop and mobile, except IE (Edge seems to support): see full support list.

function(elem) {
  return elem.querySelectorAll(':scope > someselector');
};

Complete :scope polyfill

As avetisk has mentioned Selectors API 2 uses :scope pseudo-selector.
To make this work in all browsers (that support querySelector) here is the polyfill

(function(doc, proto) {
  try { // check if browser supports :scope natively
    doc.querySelector(':scope body');
  } catch (err) { // polyfill native methods if it doesn't
    ['querySelector', 'querySelectorAll'].forEach(function(method) {
      var nativ = proto[method];
      proto[method] = function(selectors) {
        if (/(^|,)\s*:scope/.test(selectors)) { // only if selectors contains :scope
          var id = this.id; // remember current element id
          this.id = 'ID_' + Date.now(); // assign new unique id
          selectors = selectors.replace(/((^|,)\s*):scope/g, '$1#' + this.id); // replace :scope with #ID
          var result = doc[method](selectors);
          this.id = id; // restore previous id
          return result;
        } else {
          return nativ.call(this, selectors); // use native code for other selectors
        }
      }
    });
  }
})(window.document, Element.prototype);

Usage

node.querySelector(':scope > someselector');
node.querySelectorAll(':scope > someselector');

For historical reasons, my previous solution

Based on all answers

// Caution! Prototype extending
Node.prototype.find = function(selector) {
    if (/(^\s*|,\s*)>/.test(selector)) {
        if (!this.id) {
            this.id = 'ID_' + new Date().getTime();
            var removeId = true;
        }
        selector = selector.replace(/(^\s*|,\s*)>/g, '$1#' + this.id + ' >');
        var result = document.querySelectorAll(selector);
        if (removeId) {
            this.id = null;
        }
        return result;
    } else {
        return this.querySelectorAll(selector);
    }
};

Usage

elem.find('> a');