Thanks for the help all,
This is what I ended up implementing, I'm not sure if this could be done any more elegantly, but it seems to work well.
sightly:
<div data-sly-use.hasChildren="${'hasChildren.js' @ parsys='MainContent', page=currentPage}" data-sly-unwrap> <div data-sly-test="${wcmmode.edit || hasChildren}" data-sly-unwrap> <div data-sly-resource="${'MainContent' @ resourceType='foundation/components/parsys'}"></div> </div> </div>hasChildren.js
"use strict"; use(["/libs/wcm/foundation/components/utils/ResourceUtils.js", "/libs/sightly/js/3rd-party/q.js"], function (ResourceUtils, Q) { var result = false; var childPromise = Q.defer(); if(this.page.getContentResource(this.parsys) != null) { ResourceUtils.getResource(this.page.getContentResource(this.parsys).getPath()).then(function(res) { res.getChildren().then(function (childItems) { childPromise.resolve(childItems.length > 0); }, function (error) { childPromise.resolve(false); }); }, function (error) { childPromise.resolve(false); }); return childPromise.promise; } });