DOM-дерево
В соответствии с объектной моделью документа («Document Object Model», коротко DOM), каждый HTML-тег является объектом. Вложенные теги являются «детьми» родительского элемента. Текст, который находится внутри тега, также является объектом.
Все эти объекты доступны при помощи JavaScript, мы можем использовать их для изменения страницы.
Например, document.body – объект для тега <body> .
Если запустить этот код, то <body> станет красным на 3 секунды:
Это был лишь небольшой пример того, что может DOM. Скоро мы изучим много способов работать с DOM, но сначала нужно познакомиться с его структурой.
Пример DOM
Начнём с такого, простого, документа:
DOM – это представление HTML-документа в виде дерева тегов. Вот как оно выглядит:
На рисунке выше узлы-элементы можно кликать, и их дети будут скрываться и раскрываться.
Каждый узел этого дерева – это объект.
Теги являются узлами-элементами (или просто элементами). Они образуют структуру дерева: <html> – это корневой узел, <head> и <body> его дочерние узлы и т.д.
Текст внутри элементов образует текстовые узлы, обозначенные как #text . Текстовый узел содержит в себе только строку текста. У него не может быть потомков, т.е. он находится всегда на самом нижнем уровне.
Например, в теге <title> есть текстовый узел "О лосях" .
Обратите внимание на специальные символы в текстовых узлах:
- перевод строки: ↵ (в JavaScript он обозначается как \n )
- пробел: ␣
Пробелы и переводы строки – это полноправные символы, как буквы и цифры. Они образуют текстовые узлы и становятся частью дерева DOM. Так, в примере выше в теге <head> есть несколько пробелов перед <title> , которые образуют текстовый узел #text (он содержит в себе только перенос строки и несколько пробелов).
Существует всего два исключения из этого правила:
- По историческим причинам пробелы и перевод строки перед тегом <head> игнорируются
- Если мы записываем что-либо после закрывающего тега </body> , браузер автоматически перемещает эту запись в конец body , поскольку спецификация HTML требует, чтобы всё содержимое было внутри <body> . Поэтому после закрывающего тега </body> не может быть никаких пробелов.
В остальных случаях всё просто – если в документе есть пробелы (или любые другие символы), они становятся текстовыми узлами дерева DOM, и если мы их удалим, то в DOM их тоже не будет.
Здесь пробельных текстовых узлов нет:
Когда мы работаем с деревом DOM, используя инструменты разработчика в браузере (которые мы рассмотрим позже), пробелы в начале/конце текста и пустые текстовые узлы (переносы строк) между тегами обычно не отображаются.
Таким образом инструменты разработки экономят место на экране.
В дальнейших иллюстрациях DOM мы также будем для краткости пропускать пробельные текстовые узлы там, где они не имеют значения. Обычно они не влияют на то, как отображается документ.
Автоисправление
Если браузер сталкивается с некорректно написанным HTML-кодом, он автоматически корректирует его при построении DOM.
Например, в начале документа всегда должен быть тег <html> . Даже если его нет в документе – он будет в дереве DOM, браузер его создаст. То же самое касается и тега <body> .
Например, если HTML-файл состоит из единственного слова "Привет" , браузер обернёт его в теги <html> и <body> , добавит необходимый тег <head> , и DOM будет выглядеть так:
При генерации DOM браузер самостоятельно обрабатывает ошибки в документе, закрывает теги и так далее.
Есть такой документ с незакрытыми тегами:
…Но DOM будет нормальным, потому что браузер сам закроет теги и восстановит отсутствующие детали:
Важный «особый случай» – работа с таблицами. По стандарту DOM у них должен быть <tbody> , но в HTML их можно написать (официально) без него. В этом случае браузер добавляет <tbody> в DOM самостоятельно.
Для такого HTML:
DOM-структура будет такой:
Видите? Из пустоты появился <tbody> , как будто документ и был таким. Важно знать об этом, иначе при работе с таблицами возможны сюрпризы.
Другие типы узлов
Есть и некоторые другие типы узлов, кроме элементов и текстовых узлов.
Здесь мы видим узел нового типа – комментарий, обозначенный как #comment , между двумя текстовыми узлами.
Казалось бы – зачем комментарий в DOM? Он никак не влияет на визуальное отображение. Но есть важное правило: если что-то есть в HTML, то оно должно быть в DOM-дереве.
Все, что есть в HTML, даже комментарии, является частью DOM.
Даже директива <!DOCTYPE. > , которую мы ставим в начале HTML, тоже является DOM-узлом. Она находится в дереве DOM прямо перед <html> . Мы не будем рассматривать этот узел, мы даже не рисуем его на наших диаграммах, но он существует.
Даже объект document , представляющий весь документ, формально является DOM-узлом.
Существует 12 типов узлов. Но на практике мы в основном работаем с 4 из них:
- document – «входная точка» в DOM.
- узлы-элементы – HTML-теги, основные строительные блоки.
- текстовые узлы – содержат текст.
- комментарии – иногда в них можно включить информацию, которая не будет показана, но доступна в DOM для чтения JS.
Поэкспериментируйте сами
Чтобы посмотреть структуру DOM в реальном времени, попробуйте Live DOM Viewer. Просто введите что-нибудь в поле, и ниже вы увидите, как меняется DOM.
Другой способ исследовать DOM – это использовать инструменты разработчика браузера. Это то, что мы каждый день делаем при разработке.
Для этого откройте страницу elks.html, включите инструменты разработчика и перейдите на вкладку Elements.
Выглядит примерно так:

Вы можете увидеть DOM, понажимать на элементы, детально рассмотреть их и так далее.
Обратите внимание, что структура DOM в инструментах разработчика отображается в упрощённом виде. Текстовые узлы показаны как простой текст. И кроме пробелов нет никаких «пустых» текстовых узлов. Ну и отлично, потому что большую часть времени нас будут интересовать узлы-элементы.
Клик по этой кнопке в левом верхнем углу инспектора позволяет при помощи мыши (или другого устройства ввода) выбрать элемент на веб-странице и «проинспектировать» его (браузер сам найдёт и отметит его во вкладке Elements). Этот способ отлично подходит, когда у нас огромная HTML-страница (и соответствующий ей огромный DOM), и мы хотим увидеть, где находится интересующий нас элемент.
Есть и другой способ сделать это: можно кликнуть на странице по элементу правой кнопкой мыши и в контекстном меню выбрать «Inspect».

В правой части инструментов разработчика находятся следующие подразделы:
- Styles – здесь мы видим CSS, применённый к текущему элементу: правило за правилом, включая встроенные стили (выделены серым). Почти всё можно отредактировать на месте, включая размеры, внешние и внутренние отступы.
- Computed – здесь мы видим итоговые CSS-свойства элемента, которые он приобрёл в результате применения всего каскада стилей (в том числе унаследованные свойства и т.д.).
- Event Listeners – в этом разделе мы видим обработчики событий, привязанные к DOM-элементам (мы поговорим о них в следующей части учебника).
- … и т.д.
Лучший способ изучить инструменты разработчика – это прокликать их. Большинство значений можно менять и тут же смотреть результат.
Взаимодействие с консолью
При работе с DOM нам часто требуется применить к нему JavaScript. Например: получить узел и запустить какой-нибудь код для его изменения, чтобы посмотреть результат. Вот несколько подсказок, как перемещаться между вкладками Elements и Console.
- На вкладке Elements выберите первый элемент <li> .
- Нажмите Esc – прямо под вкладкой Elements откроется Console.
Последний элемент, выбранный во вкладке Elements, доступен в консоли как $0 ; предыдущий, выбранный до него, как $1 и т.д.
Теперь мы можем запускать на них команды. Например $0.style.background = ‘red’ сделает выбранный элемент красным, как здесь:

Это мы посмотрели как получить узел из Elements в Console.
Есть и обратный путь: если есть переменная node , ссылающаяся на DOM-узел, можно использовать в консоли команду inspect(node) , чтобы увидеть этот элемент во вкладке Elements.
Или мы можем просто вывести DOM-узел в консоль и исследовать «на месте», как document.body ниже:

Это может быть полезно для отладки. В следующей главе мы рассмотрим доступ и изменение DOM при помощи JavaScript.
Инструменты разработчика браузера отлично помогают в разработке: мы можем исследовать DOM, пробовать с ним что-то делать и смотреть, что идёт не так.
Итого
HTML/XML документы представлены в браузере в виде DOM-дерева.
- Теги становятся узлами-элементами и формируют структуру документа.
- Текст становится текстовыми узлами.
- … и т.д. Всё, что записано в HTML, есть и в DOM-дереве, даже комментарии.
Для изменения элементов или проверки DOM-дерева мы можем использовать инструменты разработчика в браузере.
Здесь мы рассмотрели основы, наиболее часто используемые и важные действия для начала разработки. Подробную документацию по инструментам разработки Chrome Developer Tools можно найти на странице https://developers.google.com/web/tools/chrome-devtools. Лучший способ изучить инструменты – походить по разным вкладкам, почитать меню: большинство действий очевидны для пользователя. Позже, когда вы немного их изучите, прочитайте документацию и узнайте то, что осталось.
У DOM-узлов есть свойства и методы, которые позволяют выбирать любой из элементов, изменять, перемещать их на странице и многое другое. Мы вернёмся к ним в последующих разделах.
The Document Object Model (DOM)
Now that you know the basics of the JavaScript language, we can learn how to use that language to add some interactivity to our web pages. Specifically, we will learn how to respond to user interactions, modify the contents of elements, and add/remove style classes to alter formatting.
Adding Scripts to the Page
The browser only knows about the HTML page it loads, and other files that it links to. So to add some script to our web page, we need to add an element that points to the script file. That element looks like this:
Strangely enough, you do need both a start and end tag, even though the element should have no content. The src attribute can be an absolute or relative URL to your script file. Absolute paths are typically used when loading a library of functions from a CDN location, while a relative path will be used to load your own JavaScript files from a js sub-folder.
You can add as many <script> elements to a page as you want. The browser will download and execute each script in order, and they all will share a common global name space. So if the first script defines a global variable or function, scripts added after that one will also be able to reference that variable, or call that function, defined in the previous script.
Because the browser pauses to download and execute scripts when it encounters them, we typically put these <script> elements at the end of the <body> section, just before the </body> tag. That way the page content will render and the user can click on hyperlinks while the scripts are still downloading.
Most browsers now support adding a defer attribute to the <script> element that tells the browser to defer downloading and running the script until the page is fully loaded and rendered to the screen. With this attribute, you can put the <script> element anywhere in the page. But beware about this for the short-term: it’s not supported in older browsers like IE 8. Those browsers will simply download and execute the script as soon as they encounter the <script> element.
The Document Object Model (DOM)
When the browser executes a script, it adds a few objects to the global name space that are just «there.» You don’t have to create these objects or load them from anywhere—they are simply available because the browser added them before running your script.
These global objects, and the objects they link to, are known as the Document Object Model (DOM). The DOM contains a JavaScript object for each element in your web page, organized in a tree data structure just like the elements. The root of that tree is accessible via a browser-supplied global variable named document . That variable is an object that represents the entire page, and it has many properties and methods you can use to traverse, interrogate, and even manipulate the elements within then page.
Getting References to Elements
To interrogate or manipulate an element in your page, you first need to get a reference to the corresponding DOM Element object that the browser created for that element when it parsed the page. This can be done using one of two methods.
If the element you want to interact with has an id attribute, you can use document.getElementById() to get a reference to it. For example, this line of code would get a reference to the element with an id attribute set to first-name-input :
This method works only for elements with an id attribute, but there’s another much more flexible and powerful method that will let you select elements using the same CSS selector syntax you’ve already learned. The method is document.querySelector() , and this is how you would use it to select the first element with the style class output-paragraph :
The document.querySelector() method accepts any sort of CSS selector: element, ID, class, descendant, group, etc. For example, this selector will find the <tbody> element that exists within an element with the style class output-table :
Note that document.querySelector() finds only the first element that satisfies that selector. To get all elements that satisfy the given selector, use document.querySelectorAll() . That method will return a NodeList object, which is like an array, but not quite. It has a .length property and you can retrieve an element by index, but it doesn’t support all the other methods that JavaScript arrays currently support. The safest way to iterate a NodeList at the present time is to use a standard for loop:
Getting/Setting The Content of an Element
Once you have a reference to an element, you can do several things with it. First, you can get or set its content using the textContent property:
The textContent property is considered «safe,» meaning that if you try to set it to a string that contains HTML, the browser will not interpret the string as HTML, and will instead display the HTML as plain text inside the element. This is a good thing. When we build web applications, these strings often come from the user in the first place, and devious users will often try to enter crafty HTML that when executed, can steal private information from a user. This is known as a Code Injection Attack, and it can be avoided by using this textContent property when setting an element’s content.
There is another property named innerHTML that is not safe. It sets the element’s content, but that content will be interpreted as HTML, and may result in code being executed. This is generally not a good property to use unless you are absolutely certain the content came from a trusted source.
You can also clear the content within an element by setting the textContent or innerHTML properties to an empty string:
Getting/Setting Attributes
You can also get or set any attributes that might be supported by an element you select. Each attribute is typically exposed as a property of the returned element. So if you want to change the src attribute of an img element to show a different picture, you would use code like this:
If you want to get all attributes, or if you’re not sure which attributes are available on the element, use the .attributes property, which returns a NamedNodeMap object. This isn’t commonly necessary, but it can be handy in cases where you are trying to write code that works with any kind of element.
Getting/Setting the Value of an Input
The <input> element is used to gather input from the user, but it is a self-closing tag, and thus doesn’t have any content. The value the user types into the input is actually stored in a value property which you can get or set. This property is updated every time the user types into the input.
Getting/Setting the Selected Option of a Select
The <select> and <option> elements are used to let the user choose from a fixed list of available options. The associated DOM element also has a value property which you can use to get the value attribute of the selected <option> element. But if you want to get the display text of the <option> element instead, you can use the .selectedIndex property to get the selected option’s index, and then access the option element object to get its content:
Adding/Removing Style Classes
In addition to manipulating the content of element, you can also alter its formatting via JavaScript. The best way to do this is to add or remove CSS style classes that are defined in your stylesheet. Adding a new class to an element is done like so:
Removing a style class is done using .classList.remove() .
If you want to modify just one specific style property and leave the list of style classes alone, you can do that using the element’s .style property. For example, this change the element’s background-color style (note the name in JavaScript is backgroundColor ):
Listening for Events
All of this manipulation is neat, but you typically want to perform this manipulation in response to some kind of user interaction: clicking, typing, scrolling, etc. Since these events occur after the page has loaded, and after your script has run, you need to ask the browser to call some of your code whenever these events occur. You can do that using the element’s .addEventListener() method.
For example, say you have a <button> element in your page, and you want the browser to run some code whenever the user clicks that button. You first get a reference to the DOM Element object for that button, and then pass a function reference to its .addEventListener() method:
Each time the user clicks the button, the browser will call your onButtonClick() function. In that function you can select other elements, manipulate their content, or add/remove style classes.
Note that the second parameter to .addEventListener() is just the name of the function with no parentheses after it. That name is like a variable name. It refers to the function. Putting parentheses after the name would call the function, and pass the function’s return value as the second parameter to .addEventListener() , which is not what you want. When registering an event listener, always pass a function reference; don’t call the function. You want the browser to call your function later. Passing the function reference to the browser allows it to call your function whenever the event occurs.
You can alternatively provide the event listener function in-line if you want to, and this is commonly done in the JavaScript world. Instead of defining the event listener as a function with a name, and passing that name as a function reference, you can provide an inline anonymous function:
Notice that we simply moved the function declaration down into the spot where we had previously used the function name. This is known as a function value and it doesn’t need a name anymore, as the function is declared and passed as a reference in one operation.
Either approach works, but the latter is more compact and doesn’t require naming the function, so it’s commonly used by professionals.
As the name implies, .addEventListener() will add a function to the list of listeners for that event. You can add multiple functions for the same event, and the browser will call all of them, in the order they were added.
This is good for code re-use: JavaScript libraries can safely add event listeners without having to coordinate with other code that might be added to the same page. Initially, the DOM supported only one event listener for a given element, and the listener was registered by setting a property named onEventName , where EventName was the name of the event you wanted to listen for. If another bit of script reset that property, the browser would only call the newly set function, and the previous one as well. The .addEventListener() method was added to fix this problem, so it’s good practice to use it.
The .addEventListener() also enabled something the previous mechanism didn’t support at all: adding a listener that should be called only once for the next occurrence of the event. This is handy when you need to clean up something after an asynchronous operation is complete (e.g., an element animation). To register a one-time event listener, just pass a JavaScript object with a property named once set to true as the third parameter:
Commonly-Used Events
For a full list of events you can listen for, see the Event Reference, but the following sections describe several of the most commonly-used events.
Mouse Events
Every HTML element will raise a «click» event when the element is clicked. This will also occur on touch screens when the element is tapped, though after a very short delay. Touch screens will also raise touchstart and touchend events when the user starts and stops touching an element.
Elements also raise a «doubleclick» event when the element is double-clicked/tapped, and «contextmenu» when the user clicks with the alternate button.
Window Events
When the user scrolls the page, the window object (another global like document ) will raise a «scroll» event. This allows you to alter the page as the user scrolls down. For example, a navigation bar might start scrolling with the overall page, but become fixed to the top of the viewport once it reaches the top of the viewport.
If the user resizes the browser window, the window object will raise a «resize» event. This allows you to adjust your page layout in ways that go beyond what you can do with CSS media rules.
Input Events
As noted earlier, <input> elements create a box into which users can enter text. These elements raise an event named «input» whenever the contents of the box is changed by the user. This happens with each keystroke, so it’s a handy way to respond as the user types:
These elements raise another event name «change» , but this fires only when the user tabs or clicks out of the input box (known as «losing focus»). This event can be useful when you want to let the user type a longer bit of text and only process it once the user leaves the input.
Animation Events
Adding a style class that refers to an animation will cause the browser to animate the element asynchronously. But if you try to add that same style class again to the element, the browser will simply ignore that operation, as the class already exists on the element. Attempting to remove the class and add it again in two successive lines won’t work either, as the browser will wait to look for style class changes until your event listener function completes.
To trigger an animation repeatedly, you must listen for the «animationend» event that will be raised once the browser has finished animating the element. During this event, your code can remove the style class. That way, the next time you add that style class, the browser will notice that it wasn’t there before, and animate the element again.
For example, this code adds the bounce animation style class from the animate.css stylesheet to an element each time a button is clicked:
Note that I added the
Conclusion
The DOM plus the ability to add event listener functions gives us total control over our web pages. We can literally rewrite the page in response to user interactions, which allows us to build highly-interactive web sites and applications.
Now try some of this yourself. Use this CodePen or create your own page and script.
Introduction to the DOM
The Document Object Model (DOM) is the data representation of the objects that comprise the structure and content of a document on the web. This guide will introduce the DOM, look at how the DOM represents an HTML document in memory and how to use APIs to create web content and applications.
What is the DOM?
The Document Object Model (DOM) is a programming interface for web documents. It represents the page so that programs can change the document structure, style, and content. The DOM represents the document as nodes and objects; that way, programming languages can interact with the page.
A web page is a document that can be either displayed in the browser window or as the HTML source. In both cases, it is the same document but the Document Object Model (DOM) representation allows it to be manipulated. As an object-oriented representation of the web page, it can be modified with a scripting language such as JavaScript.
For example, the DOM specifies that the querySelectorAll method in this code snippet must return a list of all the <p> elements in the document:
All of the properties, methods, and events available for manipulating and creating web pages are organized into objects. For example, the document object that represents the document itself, any table objects that implement the HTMLTableElement DOM interface for accessing HTML tables, and so forth, are all objects.
The DOM is built using multiple APIs that work together. The core DOM defines the entities describing any document and the objects within it. This is expanded upon as needed by other APIs that add new features and capabilities to the DOM. For example, the HTML DOM API adds support for representing HTML documents to the core DOM, and the SVG API adds support for representing SVG documents.
DOM and JavaScript
The previous short example, like nearly all examples, is JavaScript. That is to say, it is written in JavaScript, but uses the DOM to access the document and its elements. The DOM is not a programming language, but without it, the JavaScript language wouldn’t have any model or notion of web pages, HTML documents, SVG documents, and their component parts. The document as a whole, the head, tables within the document, table headers, text within the table cells, and all other elements in a document are parts of the document object model for that document. They can all be accessed and manipulated using the DOM and a scripting language like JavaScript.
The DOM is not part of the JavaScript language, but is instead a Web API used to build websites. JavaScript can also be used in other contexts. For example, Node.js runs JavaScript programs on a computer, but provides a different set of APIs, and the DOM API is not a core part of the Node.js runtime.
The DOM was designed to be independent of any particular programming language, making the structural representation of the document available from a single, consistent API. Even if most web developers will only use the DOM through JavaScript, implementations of the DOM can be built for any language, as this Python example demonstrates:
For more information on what technologies are involved in writing JavaScript on the web, see JavaScript technologies overview.
Accessing the DOM
You don’t have to do anything special to begin using the DOM. You use the API directly in JavaScript from within what is called a script, a program run by a browser.
When you create a script, whether inline in a <script> element or included in the web page, you can immediately begin using the API for the document or window objects to manipulate the document itself, or any of the various elements in the web page (the descendant elements of the document). Your DOM programming may be something as simple as the following example, which displays a message on the console by using the console.log() function:
As it is generally not recommended to mix the structure of the page (written in HTML) and manipulation of the DOM (written in JavaScript), the JavaScript parts will be grouped together here, and separated from the HTML.
For example, the following function creates a new h1 element, adds text to that element, and then adds it to the tree for the document:
Fundamental data types
This page tries to describe the various objects and types in simple terms. But there are a number of different data types being passed around the API that you should be aware of.
Note: Because the vast majority of code that uses the DOM revolves around manipulating HTML documents, it’s common to refer to the nodes in the DOM as elements, although strictly speaking not every node is an element.
The following table briefly describes these data types.
- list.item(1)
- list[1]
There are also some common terminology considerations to keep in mind. It’s common to refer to any Attr node as an attribute , for example, and to refer to an array of DOM nodes as a nodeList . You’ll find these terms and others to be introduced and used throughout the documentation.
DOM interfaces
This guide is about the objects and the actual things you can use to manipulate the DOM hierarchy. There are many points where understanding how these work can be confusing. For example, the object representing the HTML form element gets its name property from the HTMLFormElement interface but its className property from the HTMLElement interface. In both cases, the property you want is in that form object.
But the relationship between objects and the interfaces that they implement in the DOM can be confusing, and so this section attempts to say a little something about the actual interfaces in the DOM specification and how they are made available.
Interfaces and objects
Many objects implement several different interfaces. The table object, for example, implements a specialized HTMLTableElement interface, which includes such methods as createCaption and insertRow . But since it’s also an HTML element, table implements the Element interface described in the DOM Element Reference chapter. And finally, since an HTML element is also, as far as the DOM is concerned, a node in the tree of nodes that make up the object model for an HTML or XML page, the table object also implements the more basic Node interface, from which Element derives.
When you get a reference to a table object, as in the following example, you routinely use all three of these interfaces interchangeably on the object, perhaps without knowing it.
Core interfaces in the DOM
This section lists some of the most commonly-used interfaces in the DOM. The idea is not to describe what these APIs do here but to give you an idea of the sorts of methods and properties you will see very often as you use the DOM. These common APIs are used in the longer examples in the DOM Examples chapter at the end of this book.
The document and window objects are the objects whose interfaces you generally use most often in DOM programming. In simple terms, the window object represents something like the browser, and the document object is the root of the document itself. Element inherits from the generic Node interface, and together these two interfaces provide many of the methods and properties you use on individual elements. These elements may also have specific interfaces for dealing with the kind of data those elements hold, as in the table object example in the previous section.
The following is a brief list of common APIs in web and XML page scripting using the DOM.
Examples
Setting text content
This example uses a <div> element containing a <textarea> and two <button> elements. When the user clicks the first button we set some text in the <textarea> . When the user clicks the second button we clear the text. We use:
DOM tree
According to the Document Object Model (DOM), every HTML tag is an object. Nested tags are “children” of the enclosing one. The text inside a tag is an object as well.
All these objects are accessible using JavaScript, and we can use them to modify the page.
For example, document.body is the object representing the <body> tag.
Running this code will make the <body> red for 3 seconds:
Here we used style.background to change the background color of document.body , but there are many other properties, such as:
- innerHTML – HTML contents of the node.
- offsetWidth – the node width (in pixels)
- …and so on.
Soon we’ll learn more ways to manipulate the DOM, but first we need to know about its structure.
An example of the DOM
Let’s start with the following simple document:
The DOM represents HTML as a tree structure of tags. Here’s how it looks:
On the picture above, you can click on element nodes and their children will open/collapse.
Every tree node is an object.
Tags are element nodes (or just elements) and form the tree structure: <html> is at the root, then <head> and <body> are its children, etc.
The text inside elements forms text nodes, labelled as #text . A text node contains only a string. It may not have children and is always a leaf of the tree.
For instance, the <title> tag has the text "About elk" .
Please note the special characters in text nodes:
- a newline: ↵ (in JavaScript known as \n )
- a space: ␣
Spaces and newlines are totally valid characters, like letters and digits. They form text nodes and become a part of the DOM. So, for instance, in the example above the <head> tag contains some spaces before <title> , and that text becomes a #text node (it contains a newline and some spaces only).
There are only two top-level exclusions:
- Spaces and newlines before <head> are ignored for historical reasons.
- If we put something after </body> , then that is automatically moved inside the body , at the end, as the HTML spec requires that all content must be inside <body> . So there can’t be any spaces after </body> .
In other cases everything’s straightforward – if there are spaces (just like any character) in the document, then they become text nodes in the DOM, and if we remove them, then there won’t be any.
Here are no space-only text nodes:
Browser tools (to be covered soon) that work with DOM usually do not show spaces at the start/end of the text and empty text nodes (line-breaks) between tags.
Developer tools save screen space this way.
On further DOM pictures we’ll sometimes omit them when they are irrelevant. Such spaces usually do not affect how the document is displayed.
Autocorrection
If the browser encounters malformed HTML, it automatically corrects it when making the DOM.
For instance, the top tag is always <html> . Even if it doesn’t exist in the document, it will exist in the DOM, because the browser will create it. The same goes for <body> .
As an example, if the HTML file is the single word "Hello" , the browser will wrap it into <html> and <body> , and add the required <head> , and the DOM will be:
While generating the DOM, browsers automatically process errors in the document, close tags and so on.
A document with unclosed tags:
…will become a normal DOM as the browser reads tags and restores the missing parts:
An interesting “special case” is tables. By DOM specification they must have <tbody> tag, but HTML text may omit it. Then the browser creates <tbody> in the DOM automatically.
DOM-structure will be:
You see? The <tbody> appeared out of nowhere. We should keep this in mind while working with tables to avoid surprises.
Other node types
There are some other node types besides elements and text nodes.
For example, comments:
We can see here a new tree node type – comment node, labeled as #comment , between two text nodes.
We may think – why is a comment added to the DOM? It doesn’t affect the visual representation in any way. But there’s a rule – if something’s in HTML, then it also must be in the DOM tree.
Everything in HTML, even comments, becomes a part of the DOM.
Even the <!DOCTYPE. > directive at the very beginning of HTML is also a DOM node. It’s in the DOM tree right before <html> . Few people know about that. We are not going to touch that node, we even don’t draw it on diagrams, but it’s there.
The document object that represents the whole document is, formally, a DOM node as well.
There are 12 node types. In practice we usually work with 4 of them:
- document – the “entry point” into DOM.
- element nodes – HTML-tags, the tree building blocks.
- text nodes – contain text.
- comments – sometimes we can put information there, it won’t be shown, but JS can read it from the DOM.
See it for yourself
To see the DOM structure in real-time, try Live DOM Viewer. Just type in the document, and it will show up as a DOM at an instant.
Another way to explore the DOM is to use the browser developer tools. Actually, that’s what we use when developing.
To do so, open the web page elk.html, turn on the browser developer tools and switch to the Elements tab.
It should look like this:
You can see the DOM, click on elements, see their details and so on.
Please note that the DOM structure in developer tools is simplified. Text nodes are shown just as text. And there are no “blank” (space only) text nodes at all. That’s fine, because most of the time we are interested in element nodes.
Clicking the button in the left-upper corner allows us to choose a node from the webpage using a mouse (or other pointer devices) and “inspect” it (scroll to it in the Elements tab). This works great when we have a huge HTML page (and corresponding huge DOM) and would like to see the place of a particular element in it.
Another way to do it would be just right-clicking on a webpage and selecting “Inspect” in the context menu.
At the right part of the tools there are the following subtabs:
- Styles – we can see CSS applied to the current element rule by rule, including built-in rules (gray). Almost everything can be edited in-place, including the dimensions/margins/paddings of the box below.
- Computed – to see CSS applied to the element by property: for each property we can see a rule that gives it (including CSS inheritance and such).
- Event Listeners – to see event listeners attached to DOM elements (we’ll cover them in the next part of the tutorial).
- …and so on.
The best way to study them is to click around. Most values are editable in-place.
Interaction with console
As we work the DOM, we also may want to apply JavaScript to it. Like: get a node and run some code to modify it, to see the result. Here are few tips to travel between the Elements tab and the console.
- Select the first <li> in the Elements tab.
- Press Esc – it will open console right below the Elements tab.
Now the last selected element is available as $0 , the previously selected is $1 etc.
We can run commands on them. For instance, $0.style.background = ‘red’ makes the selected list item red, like this:
That’s how to get a node from Elements in Console.
There’s also a road back. If there’s a variable referencing a DOM node, then we can use the command inspect(node) in Console to see it in the Elements pane.
Or we can just output the DOM node in the console and explore “in-place”, like document.body below:
That’s for debugging purposes of course. From the next chapter on we’ll access and modify DOM using JavaScript.
The browser developer tools are a great help in development: we can explore the DOM, try things and see what goes wrong.
Summary
An HTML/XML document is represented inside the browser as the DOM tree.
- Tags become element nodes and form the structure.
- Text becomes text nodes.
- …etc, everything in HTML has its place in DOM, even comments.
We can use developer tools to inspect DOM and modify it manually.
Here we covered the basics, the most used and important actions to start with. There’s an extensive documentation about Chrome Developer Tools at https://developers.google.com/web/tools/chrome-devtools. The best way to learn the tools is to click here and there, read menus: most options are obvious. Later, when you know them in general, read the docs and pick up the rest.
DOM nodes have properties and methods that allow us to travel between them, modify them, move around the page, and more. We’ll get down to them in the next chapters.