
Shadow DOM é uma especificação (ainda em status de rascunho) que faz parte do recente trabalho Web Components da W3C, que é composto por mais 3 partes: templates, decorators e custom elements – falaremos mais sobre estes novíssimos recursos futuramente por aqui no Loop Infinito. Corrijam-me se eu estiver falando besteira, mas acredito que o Web Components será um trabalho estável apenas quem sabe num suposto HTML6.
Shadow DOM é simplesmente uma sub-árvore de elementos DOM que pode ser aninhada dentro de outro elemento (host). A diferença é que, quando um elemento qualquer possui uma shadow DOM, seus elementos filhos comuns não são renderizados, em vez disso, o conteúdo da shadow DOM que é renderizado.
Na verdade, a shadow DOM existe desde os primórdios da web, e sempre esteve presente em nossos navegadores para que a componentização viesse a se tornar possível. A novidade aqui é que este recurso agora torna-se acessível a nós, desenvolvedores. Agora vamos entender como funciona.
Visão estrutural
Como mencionei anteriormente, uma shadow DOM pode ser aninhada a qualquer elemento, chamaremos este elemento de host. E qualquer elemento (host) pode ter várias shadow DOMs (figura acima). No momento da renderização, o conteúdo dentro de host é substituído pelo conteúdo da shadow DOM (figura abaixo). Os lugares onde os elementos da sub-árvore shadow são inseridos em host são chamados de pontos de inserção. No exemplo abaixo, temos 2 pontos de inserção (os 2 filhos de shadow host).
Encapsulamento faz todo o sentido
Uma das grandes razões para a implementação da Shadow DOM pelos navegadores é para poder manter seus widgets inalteráveis, isolando-os de todo tipo de acesso – ou seja, mantendo tudo dentro de uma caixa preta.
Sabe esses componentes de interface que usamos em nossas aplicações como <select>
(combo box) e <input>
dos tipos text
, range
, number
, color
, datetime
etc? Pois bem, estes componentes não passam de elementos HTML estilizados com CSS de acordo com o estilo de cada plataforma, acredite. A grande diferença é o encapsulamento.
Por exemplo, sabemos que o elemento <input type="range">
se parece com o seguinte:

O input range
visivelmente é composto basicamente por 2 partes: uma trilha e um botão – o qual é possível deslizar pela trilha.
Sabemos que não temos acesso aos elementos internos do componente/widget, não podemos manipula-los e nem mesmo estiliza-los, justamente porque não temos acesso a shadow DOM do elemento. Para ilustrar este exemplo, suponha que tenhamos:
<input type="range" id="slider" />
Se tentarmos obter o primeiro elemento filho de #slider
via JavaScript:
var slider = document.getElementsById( "slider" )
console.log( slider.firstChild ) // retorna null
Nada é retornado, mas como isto é possível, então? Isso é a shadow DOM em ação. Apenas precisamos incluir <input type="range">
em nosso código e o navegador se vira com o resto, ou seja, com a montagem estrutural e com a renderização do componente por completo.
Este tipo de coisa acontece muito, os componentes são encapsulados em apenas um elemento (definido no código) que age como uma caixa preta, mas o que rola por baixo dos panos é algo bem mais complexo.

O elemento <input type="range">
é bem simples em relação a outros, como por exemplo <audio>
e <video>
, que possuem controles de play/pause, volume, trilha, rewind, forward, display de tempo, etc. E no caso de <video>
, ainda há o display de mídia (onde toca o vídeo) e um botão para tela cheia.
Mais liberdade
Imagine poder ter acesso aos elementos dos componentes e poder modificar as propriedades inerentes a apresentação de qualquer um deles. Isto se torna possível com a abertura da shadow DOM.
Quando o assunto é design de UI, quem nunca desejou poder alterar os estilos dos componentes, de modo que estes apareceriam sempre de forma igual independente de plataforma? Por exemplo, poder estilizar o player de vídeo mostrado acima com as cores da sua aplicação.
Tente você
Com o navegador Google Chrome é possível visualizar a shadow DOM de vários elementos de formulário pelo Web Inspector. As instruções para tornar isto possível estão neste post (em inglês).
Tentei usar a ShadowRoot API para implementar algum exemplo customizado de widget aqui no post, mas infelizmente esta API ainda não está disponível – nem nas versões mais novas do Google Chrome Canary e Webkit. Então, por enquanto ficaremos só na vontade, e assim que soubermos de algo, prometo fazer um post sobre criação de widgets com a Shadow DOM.
No próximo post falarei sobre estilização de widgets de formulário com CSS através de novos seletores e propriedades que permitem o alcance aos estilos da shadow DOM.