I think this is implicit in your design, but it would be good to make it explicit. For example it would be great to show how to implement e.g. <img>. My understanding is it would be something like this:
// In UA code setting up a new <img>
this.addEventListener("ariarequest", ev => {
if (ev.attributeName === "labelledby") {
if (this.hasAttribute("alt")) {
ev.attributeValue = this.getAttribute("alt");
}
if (this.hasAttribute("title")) {
ev.attributeValue = this.getAttribute("title");
}
} else if (ev.attributeName === "describedby") {
if (this.hasAttribute("title")) {
ev.attributeValue = this.getAttribute("title");
}
} else if (ev.attributeName === "role") {
if (this.hasAttribute("alt") && this.getAttribute("alt").trim() !== "") {
ev.attributeValue = "img";
} else {
ev.attributeValue = "presentation";
}
}
});