Свойства и атрибуты

Свойства и атрибуты #

Атрибуты — то, что записано в HTML (disabled, data-track-id). Свойства — поля JavaScript-объекта элемента; они могут расходиться с разметкой (например, value у <input>). Для UI JSFlow атрибуты data-* и классы часто хранят состояние, а свойства — отражают интерактивность формы.


Чтение и запись атрибутов #

const emailInput = document.querySelector('#checkout-email')

emailInput.getAttribute('type') // "email"
emailInput.setAttribute('aria-invalid', 'true')
emailInput.removeAttribute('readonly')
emailInput.hasAttribute('required') // true

getAttribute всегда возвращает строку или null. Булевы атрибуты в HTML (disabled, checked) присутствуют как пустая строка или имя атрибута:

const payBtn = document.querySelector('#pay-now')
payBtn.getAttribute('disabled') // "" если выключена, null если нет атрибута

Свойства vs атрибуты #

const qtyInput = document.querySelector('#item-qty')

qtyInput.value = '5' // свойство — текущее значение в поле
qtyInput.defaultValue // значение из исходного HTML

qtyInput.setAttribute('value', '1') // не меняет то, что видит пользователь, если value уже меняли

Типичные пары:

ЭлементАтрибутСвойствоЗаметка
inputvalue.valueсвойство — актуальный ввод
inputchecked.checkedчекбокс
buttondisabled.disabledboolean-свойство
imgsrc.srcсвойство может быть абсолютным URL

Для форм checkout опирайтесь на .value, .checked, .disabled — они синхронизированы с UI.


dataset и data-* #

Атрибуты data-* доступны через element.dataset; имена в camelCase:

<li class="track-row" data-track-id="tr-884" data-duration-sec="214">
const row = document.querySelector('.track-row')

row.dataset.trackId // "tr-884"
row.dataset.durationSec // "214" — всегда строка

row.dataset.playing = 'true'
// в DOM: data-playing="true"

Удаление:

delete row.dataset.playing

data-* удобны для делегирования: в обработчике читайте event.target.closest('[data-track-id]')?.dataset.trackId.


id и class #

const modal = document.querySelector('.checkout-modal')
modal.id = 'step-shipping' // обновит атрибут id

modal.className = 'checkout-modal is-open' // перезапишет все классы

Для точечных изменений используйте classList (подробнее в Стили и координаты):

modal.classList.add('is-open')
modal.classList.remove('is-hidden')
modal.classList.toggle('is-loading', formPending)
modal.classList.contains('is-open') // true

ARIA и доступность #

Состояние виджета дашборда можно отразить для скринридеров:

const widget = document.querySelector('[data-widget="orders"]')

widget.setAttribute('role', 'region')
widget.setAttribute('aria-label', 'Заказы за сегодня')
widget.setAttribute('aria-busy', 'true')

// после загрузки данных
widget.setAttribute('aria-busy', 'false')

Не дублируйте видимый текст в aria-label, если заголовок уже связан через aria-labelledby.


Практика: состояние плейлиста #

function markPlaying(trackId) {
  document.querySelectorAll('.track-row').forEach((row) => {
    const isActive = row.dataset.trackId === trackId
    row.classList.toggle('is-playing', isActive)
    row.setAttribute('aria-current', isActive ? 'true' : 'false')
  })
}

markPlaying('tr-884')

Итог #

  • Атрибуты — строки в разметке; свойства — живое состояние элемента.
  • Формы: читайте .value, .checked, .disabled.
  • data-* и dataset — лёгкий способ хранить ID и флаги без лишних классов.
  • classList предпочтительнее присваивания className целиком.

См. также #

Часто спрашивают

querySelector или getElementById?
getElementById быстрее и проще для одного id; querySelector гибче за счёт CSS-селекторов. Подробнее