Skip to content

Sponsor

Sponsor

Understanding Update Objects: What You Can Change

What is an "update object"?

Throughout this guide, you've seen code like this:

javascript
Elements.update({
  header: { textContent: 'Welcome!' },
  button: { disabled: true }
});

The part after each element/selector is called an update object — it's the set of instructions describing what changes you want to make.

Think of it like a form you fill out:

┌─────────────────────────────────────┐
│  ELEMENT CHANGE REQUEST             │
│                                     │
│  Element: header                    │
│  Change textContent to: 'Welcome!'  │
│                                     │
│  ☑ Approved                         │
└─────────────────────────────────────┘

The update object is that form. You write down exactly what should change, and the DOM Helpers library carries it out.

This section is a complete guide to everything you can put in that form — all the different types of changes you can request.


The six categories of changes

Every change you can make falls into one of six categories:

  1. Basic Properties — Simple one-value changes (text, value, disabled)
  2. Styles — Visual appearance (colors, sizes, spacing)
  3. Classes — Adding/removing CSS class labels
  4. Attributes — HTML attributes (data-, aria-, custom attributes)
  5. Event Listeners — What happens when users click, hover, etc.
  6. Dataset — Special data-* attributes in a cleaner format

Let's learn each one.


Category 1: Basic Properties

javascript
{
  textContent: 'New text',
  innerHTML: '<strong>HTML</strong> content',
  value: 'input value',
  disabled: true,
  checked: false,
  // ... any DOM property
}

What are "properties"?

Every element on a webpage is actually a JavaScript object with properties — like variables attached to it.

Think of an element like a person:

  • A person has a name → An element has textContent
  • A person has an age → An element has a value
  • A person can be awake or asleep → An element can be disabled or not

Properties are the simple facts about an element that you can read or change.

textContent — The readable text inside an element

What it does: Changes the text that appears inside an element.

Example:

javascript
Elements.update({
  header: { textContent: 'Welcome to our site!' }
});

Before:

html
<h1 id="header">Loading...</h1>

After:

html
<h1 id="header">Welcome to our site!</h1>

The text between the opening and closing tags changed.

Important: textContent treats everything as plain text. If you write <strong>bold</strong>, it shows literally as <strong>bold</strong> on the page — not as bold text.


innerHTML — HTML content inside an element

What it does: Changes the HTML structure inside an element.

Example:

javascript
Elements.update({
  message: { innerHTML: '<strong>Success!</strong> Your changes were saved.' }
});

Before:

html
<div id="message">Loading...</div>

After:

html
<div id="message"><strong>Success!</strong> Your changes were saved.</div>

Notice the <strong> tag actually works — the word "Success!" appears bold.

When to use which:

  • Use textContent for plain text (safer, faster)
  • Use innerHTML when you need formatting tags like <strong>, <em>, <br>, etc.

value — The content of an input field

What it does: Sets what's typed into an input, textarea, or select element.

Example:

javascript
Elements.update({
  username: { value: 'john_doe' },
  email: { value: 'john@example.com' }
});

Before:

html
<input id="username" type="text" value="">
<input id="email" type="email" value="">

After:

html
<input id="username" type="text" value="john_doe">
<input id="email" type="email" value="john@example.com">

The input fields now have content pre-filled, as if the user typed it in.


disabled — Whether an element can be interacted with

What it does: Makes an element unusable (grayed out, can't click).

Example:

javascript
Elements.update({
  submitBtn: { disabled: true },
  cancelBtn: { disabled: false }
});

Values:

  • disabled: true → Element becomes grayed out and can't be clicked
  • disabled: false → Element becomes active and clickable again

Before:

html
<button id="submitBtn">Submit</button>   <!-- clickable -->

After:

html
<button id="submitBtn" disabled>Submit</button>   <!-- grayed out, can't click -->

checked — Whether a checkbox/radio is selected

What it does: Checks or unchecks a checkbox or radio button.

Example:

javascript
Elements.update({
  termsCheckbox: { checked: true },
  newsletterCheckbox: { checked: false }
});

Values:

  • checked: true → Checkbox/radio appears selected ✅
  • checked: false → Checkbox/radio appears unselected ☐

"Any DOM property"

The comment // ... any DOM property means you can set almost any property that exists on an HTML element.

More examples:

javascript
{
  placeholder: 'Enter your name...',   // Input placeholder text
  required: true,                       // Makes an input required
  src: 'image.jpg',                     // Changes an image source
  href: 'https://example.com',          // Changes a link destination
  title: 'Hover tooltip text',          // Tooltip that appears on hover
  readOnly: true,                       // Makes an input read-only (can't edit)
  maxLength: 100                        // Limits input to 100 characters
}

If it's a property on the element, you can set it here.


Category 2: Style Updates

javascript
{
  style: {
    color: 'blue',
    backgroundColor: '#f0f0f0',
    fontSize: '16px',
    padding: '10px',
    // ... any CSS property (camelCase)
  }
}

What is style?

style is a special nested object for changing visual appearance. Everything inside the style: { } object controls how the element looks — its colors, size, spacing, borders, shadows, etc.

Important formatting rule: CSS property names in JavaScript use camelCase instead of kebab-case.

CSS (in stylesheets):        JavaScript (in style object):
──────────────────────────────────────────────────────
background-color      →      backgroundColor
font-size             →      fontSize
border-radius         →      borderRadius
padding-top           →      paddingTop

Why? Because JavaScript doesn't allow dashes in property names. background-color would be read as "background minus color" (a math operation). So we remove the dash and capitalize the next letter.


Common style properties

Colors:

javascript
{
  style: {
    color: 'red',                    // Text color
    backgroundColor: '#3b82f6',       // Background color
    borderColor: 'green'              // Border color
  }
}

Sizes:

javascript
{
  style: {
    fontSize: '18px',                 // Text size
    width: '200px',                   // Element width
    height: '100px',                  // Element height
    padding: '20px',                  // Space inside element
    margin: '10px'                    // Space outside element
  }
}

Borders:

javascript
{
  style: {
    border: '2px solid blue',         // Border all around
    borderRadius: '8px',              // Rounded corners
    borderTop: '3px dashed red'       // Border on top only
  }
}

Positioning and layout:

javascript
{
  style: {
    display: 'flex',                  // Change layout mode
    position: 'absolute',             // Positioning type
    top: '10px',                      // Distance from top
    left: '50px',                     // Distance from left
    opacity: '0.5',                   // Transparency (0 = invisible, 1 = solid)
    zIndex: '100'                     // Stacking order (higher = on top)
  }
}

A real example: Styling an alert box

javascript
Elements.update({
  alertBox: {
    style: {
      backgroundColor: '#fef2f2',     // Light red background
      color: '#991b1b',               // Dark red text
      padding: '16px',                // Space inside
      borderLeft: '4px solid #dc2626', // Thick red left border
      borderRadius: '4px',            // Slightly rounded corners
      fontSize: '14px',               // Smaller text
      marginBottom: '20px'            // Space below the box
    }
  }
});

What the user sees:

┌────────────────────────────────────────────┐
║  Warning! Please review your information  │  ← Light red bg, dark red text
║  before submitting the form.              │     Thick red left border
└────────────────────────────────────────────┘

All those styles create a professional alert box in one update.


Category 3: Class List Operations

javascript
{
  classList: {
    add: ['class1', 'class2'],
    remove: ['old-class'],
    toggle: 'active',
    replace: ['old-class', 'new-class']
  }
}

What is classList?

Every HTML element has a list of CSS classes attached to it — like labels or tags. The classList object lets you add, remove, or swap those classes.

html
<div class="card active featured"></div>
                 ↑      ↑      ↑
              Three classes attached

Why change classes instead of styles directly?

Classes are reusable. You define the style once in your CSS file, then apply it to many elements by adding the class.

CSS:

css
.highlighted {
  background-color: yellow;
  font-weight: bold;
}

JavaScript:

javascript
Elements.update({
  importantText: {
    classList: { add: 'highlighted' }
  }
});

Now importantText gets the yellow background and bold text — without writing the styles in JavaScript. You just attach the label.


add — Add one or more classes

javascript
{
  classList: {
    add: 'active'              // Add one class
  }
}

{
  classList: {
    add: ['active', 'visible'] // Add multiple classes
  }
}

Before:

html
<button id="btn" class="primary">Click</button>

After:

html
<button id="btn" class="primary active visible">Click</button>

The classes active and visible were added to the existing list. primary stayed.


remove — Remove one or more classes

javascript
{
  classList: {
    remove: 'hidden'              // Remove one class
  }
}

{
  classList: {
    remove: ['hidden', 'loading'] // Remove multiple classes
  }
}

Before:

html
<div id="content" class="container hidden loading">...</div>

After:

html
<div id="content" class="container">...</div>

The hidden and loading classes were removed. container stayed.


toggle — Flip a class on/off

javascript
{
  classList: {
    toggle: 'active'
  }
}

What "toggle" means: If the class is present, remove it. If it's not present, add it. Like a light switch — flip it and the state reverses.

Before:

html
<nav id="menu" class="sidebar">Menu</nav>

After (first toggle):

html
<nav id="menu" class="sidebar active">Menu</nav>  <!-- active added -->

After (second toggle):

html
<nav id="menu" class="sidebar">Menu</nav>  <!-- active removed -->

Great for show/hide effects, active states, and anything that switches between two modes.


replace — Swap one class for another

javascript
{
  classList: {
    replace: ['old-class', 'new-class']
  }
}

What this does: Removes old-class and adds new-class in one action.

Before:

html
<div id="status" class="status-pending">Processing...</div>

After:

html
<div id="status" class="status-complete">Processing...</div>

Perfect for changing states: pendingcomplete, light-modedark-mode, etc.


Category 4: Attributes

javascript
{
  setAttribute: {
    'data-id': '123',
    'aria-label': 'Close button'
  },
  removeAttribute: ['hidden', 'disabled']
}

What are attributes?

Attributes are the name-value pairs written inside HTML tags.

html
<button id="btn" type="submit" data-action="save" aria-label="Save changes">
         ↑       ↑             ↑               ↑
         Attributes (name="value")

You've already seen attributes like id, type, class, src, href. But you can also create your own custom attributes.


setAttribute — Add or change attributes

javascript
{
  setAttribute: {
    'data-user-id': '42',
    'aria-label': 'Navigation menu',
    'tabindex': '0'
  }
}

Before:

html
<nav id="menu"></nav>

After:

html
<nav id="menu" data-user-id="42" aria-label="Navigation menu" tabindex="0"></nav>

Three new attributes were added.

Common use cases:

  • data-* attributes for storing custom information
  • aria-* attributes for accessibility
  • tabindex for keyboard navigation order
  • title for hover tooltips
  • alt for image descriptions

removeAttribute — Delete attributes

javascript
{
  removeAttribute: ['hidden', 'disabled']
}

Before:

html
<div id="panel" hidden disabled>Content</div>

After:

html
<div id="panel">Content</div>

The hidden and disabled attributes are completely removed.

Why remove attributes? Some attributes work just by existing — like hidden, disabled, required. Even setting them to false doesn't remove them. You have to delete them entirely.

html
<!-- This is still disabled! -->
<button disabled="false">Click</button>

<!-- This works — attribute is gone -->
<button>Click</button>

Category 5: Event Listeners

javascript
{
  addEventListener: [
    'click',
    (e) => {
      console.log('Clicked!', e);
    }
  ]
}

What is an event listener?

An event listener is a piece of code that waits for something to happen — like a click, hover, key press — and then runs a function.

Think of it like a security camera. The camera (listener) watches a specific area (event type). When it detects motion (event happens), it records footage (runs your function).


Basic syntax: Array format

javascript
{
  addEventListener: ['eventName', functionToRun]
}

Two parts:

  1. 'eventName' — What you're listening for (click, hover, etc.)
  2. functionToRun — What happens when it occurs

Example:

javascript
Elements.update({
  myButton: {
    addEventListener: [
      'click',
      (e) => {
        alert('Button was clicked!');
      }
    ]
  }
});

Now when someone clicks the button with id="myButton", an alert pops up.


What is (e) =>?

This is an arrow function — a short way to write functions in JavaScript.

javascript
(e) => { console.log('Clicked!', e); }
 ↑         ↑
 │         └── What the function does
 └──────────── Parameter: the event object

The e (short for "event") is an object containing information about what happened:

  • What was clicked
  • Where the mouse was
  • What keys were pressed
  • And more...

Example using the event object:

javascript
addEventListener: [
  'click',
  (e) => {
    console.log('You clicked:', e.target.textContent);
    console.log('Mouse position:', e.clientX, e.clientY);
  }
]

Advanced syntax: Object format (multiple events)

javascript
{
  addEventListener: {
    click: (e) => console.log('Click'),
    mouseenter: (e) => console.log('Mouse entered'),
    mouseleave: (e) => console.log('Mouse left')
  }
}

This attaches three different listeners to the same element at once.

Real example: Interactive card

javascript
Elements.update({
  card: {
    addEventListener: {
      click: (e) => {
        console.log('Card clicked');
      },
      mouseenter: (e) => {
        e.target.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)';
      },
      mouseleave: (e) => {
        e.target.style.boxShadow = 'none';
      }
    }
  }
});

What happens:

  • Click the card → Logs "Card clicked"
  • Hover over card → Shadow appears
  • Move mouse away → Shadow disappears

Common event types

click       → User clicks the element
dblclick    → User double-clicks
mouseenter  → Mouse moves over the element
mouseleave  → Mouse moves away from the element
keydown     → User presses a key
keyup       → User releases a key
input       → User types in an input field
change      → An input value changes
submit      → A form is submitted
focus       → Element receives focus
blur        → Element loses focus

Category 6: Dataset

javascript
{
  dataset: {
    userId: '123',
    action: 'submit',
    value: 'custom'
  }
}

What is dataset?

dataset is a cleaner way to set data-* attributes. Every property you add to dataset automatically becomes a data-* attribute in the HTML.

These two are equivalent:

javascript
// Using setAttribute
setAttribute: {
  'data-user-id': '123',
  'data-action': 'submit'
}

// Using dataset (cleaner)
dataset: {
  userId: '123',
  action: 'submit'
}

Notice:

  • dataset.userId becomes data-user-id (camelCase → kebab-case)
  • No need to write data- over and over

Why use data-* attributes?

They let you store custom information directly on elements for later use.

Example: Storing product IDs on buttons

javascript
Selector.update({
  'button.add-to-cart': {
    dataset: {
      productId: '12345',
      productName: 'Blue Widget',
      price: '29.99'
    },
    addEventListener: [
      'click',
      (e) => {
        const id = e.target.dataset.productId;
        const name = e.target.dataset.productName;
        const price = e.target.dataset.price;
        
        console.log(`Adding ${name} ($${price}) to cart`);
        // Add to cart logic here...
      }
    ]
  }
});

What happens:

  1. Each "Add to Cart" button gets product info stored as data-* attributes
  2. When clicked, the function reads that data and knows which product was clicked
  3. No need for IDs or complex lookups — the information lives right on the button

Combining multiple categories

You can mix and match as many categories as you need in one update object.

Example: Complete button update

javascript
Elements.update({
  submitBtn: {
    // Basic properties
    textContent: 'Processing...',
    disabled: true,
    
    // Styles
    style: {
      backgroundColor: '#9ca3af',
      cursor: 'not-allowed',
      opacity: '0.7'
    },
    
    // Classes
    classList: {
      add: 'loading',
      remove: 'ready'
    },
    
    // Attributes
    setAttribute: {
      'aria-busy': 'true'
    },
    
    // Dataset
    dataset: {
      status: 'processing'
    }
  }
});

All six categories used in one update. The button:

  • Changes its text to "Processing..."
  • Becomes disabled
  • Gets grayed out visually
  • Gains the loading class, loses the ready class
  • Gets an accessibility attribute
  • Stores its status in a data attribute

One call. Six types of changes. One element completely transformed.


Error Handling: What happens when things go wrong

javascript
const results = Elements.update({
  existingElement: { textContent: 'Updated!' },
  nonExistentElement: { textContent: 'This will fail' }
});

console.log(results);

Output:

javascript
{
  existingElement: { 
    success: true, 
    element: HTMLElement 
  },
  nonExistentElement: { 
    success: false, 
    error: "Element with ID 'nonExistentElement' not found" 
  }
}

What's happening?

One element exists and gets updated successfully (success: true). The other doesn't exist and fails (success: false) with an error message explaining why.

The important part: The update keeps going. It doesn't crash. It doesn't stop. It updates what it can, reports what failed, and moves on.

This is called graceful error handling — errors are expected and managed, not catastrophic.


Checking if all updates succeeded

javascript
const results = Elements.update({
  header: { textContent: 'Welcome' },
  footer: { textContent: 'Copyright 2024' },
  sidebar: { textContent: 'Menu' }
});

// Check if all updates succeeded
const allSuccessful = Object.values(results).every((r) => r.success);

console.log(allSuccessful);  // true or false

Breaking it down

Object.values(results)
Converts the results object into an array of just the result objects (ignoring the keys).

javascript
// From this:
{
  header: { success: true, ... },
  footer: { success: true, ... }
}

// To this:
[
  { success: true, ... },
  { success: true, ... }
]

.every((r) => r.success)
Checks if every item in the array has success: true.

javascript
[
  { success: true },
  { success: true },
  { success: true }
]
// .every(r => r.success) → true (all are true)

[
  { success: true },
  { success: false },  ← One failed
  { success: true }
]
// .every(r => r.success) → false (not all are true)

The result: allSuccessful is true only if every single update worked. If even one failed, it's false.


Finding which updates failed

javascript
const results = Elements.update({
  header: { textContent: 'Welcome' },
  missingElement: { textContent: 'Fail' },
  footer: { textContent: 'Copyright' }
});

// Get failed updates
const failed = Object.entries(results)
  .filter(([_, result]) => !result.success)
  .map(([id, result]) => ({ id, error: result.error }));

console.log(failed);

Output:

javascript
[
  { 
    id: 'missingElement', 
    error: "Element with ID 'missingElement' not found" 
  }
]

Breaking it down

Object.entries(results)
Converts the results object into an array of [key, value] pairs.

javascript
// From this:
{
  header: { success: true, ... },
  missingElement: { success: false, ... }
}

// To this:
[
  ['header', { success: true, ... }],
  ['missingElement', { success: false, ... }]
]

.filter(([_, result]) => !result.success)
Keeps only the pairs where success is false.

The [_, result] part means: "Each item is an array with two parts. I don't care about the first part (the key), so I'll call it _. I care about the second part (the result object)."

The !result.success means "NOT success" — so it keeps failures only.

.map(([id, result]) => ({ id, error: result.error }))
Transforms each failed pair into a simple object with just the ID and error message.

javascript
// From this:
['missingElement', { success: false, error: "Element not found" }]

// To this:
{ id: 'missingElement', error: "Element not found" }

Using the error information

javascript
const results = Elements.update({
  /* ... */
});

const failed = Object.entries(results)
  .filter(([_, result]) => !result.success)
  .map(([id, result]) => ({ id, error: result.error }));

if (failed.length > 0) {
  console.error('Failed updates:', failed);
  
  // Maybe show a notification to the user
  alert(`Some elements couldn't be updated: ${failed.map(f => f.id).join(', ')}`);
  
  // Or log details for debugging
  failed.forEach(f => {
    console.error(`Failed to update ${f.id}: ${f.error}`);
  });
}

What this does:

  1. Runs the updates
  2. Checks if any failed
  3. If yes, logs them, shows an alert, and logs details

You can catch problems early instead of wondering why your page looks broken.


The key takeaways

Six categories of updates:

  1. Basic properties (textContent, value, disabled)
  2. Styles (style: { color, fontSize, ... })
  3. Classes (classList: { add, remove, toggle })
  4. Attributes (setAttribute, removeAttribute)
  5. Events (addEventListener)
  6. Dataset (dataset: { ... })

Error handling:

  • Updates don't crash — they fail gracefully
  • success: true/false tells you what worked
  • You can check results to catch problems early

The mental model:

"An update object is a shopping list. You list everything you want changed, hand it over, and get back a receipt showing what was available and what wasn't."

You don't need to use all six categories every time. Use what you need. Mix and match. The flexibility is the point.