Skip to content

Sponsor

Sponsor

Understanding the Basic Example

Quick Start (30 seconds)

Here is the example you'll learn to read by the end of this chapter. Right now it might look like a wall of code. By the last section, you'll read it like plain English.

javascript
Collections.update({
  'btn': { disabled: true },
  'tag:p': { style: { lineHeight: '1.6' } },
  'name:email': { placeholder: 'Enter your email' }
});

This one call says:

  • "Disable every element with class="btn""
  • "Set comfortable line spacing on every <p> element"
  • "Add a placeholder to every input with name="email""

Three different groups. One function call. Zero loops.


The Three-Layer Structure

Before breaking down each line, look at the overall shape of any Collections.update() call. It always has three layers:

Layer 1 — The Method Call
┌─────────────────────────────────────┐
│  Collections.update( ... )          │
└──────────────┬──────────────────────┘


Layer 2 — The Bulk Object
┌─────────────────────────────────────┐
│  {                                  │
│    'btn':        { ... },           │  ← one entry per collection
│    'tag:p':      { ... },           │
│    'name:email': { ... }            │
│  }                                  │
└──────────────┬──────────────────────┘


Layer 3 — The Update Object (inside each entry)
┌─────────────────────────────────────┐
│  { disabled: true }                 │  ← what changes to apply
│  { style: { lineHeight: '1.6' } }   │     to every element in
│  { placeholder: '...' }             │     that collection
└─────────────────────────────────────┘

Every time you use Collections.update(), you're building this same three-layer structure:

  1. The method call wrapping everything
  2. The bulk object mapping collection identifiers to update objects
  3. The update objects describing what changes to make

Now let's go line by line.


Line 1: Class Collections (The Default)

javascript
'btn': { disabled: true }

What does this line say?

In plain English: "Find every element with class="btn" and disable it."

Breaking down the key

'btn'

  └── No prefix? Then it's a CLASS NAME by default.
      Collections.update() assumes class unless told otherwise.

Reading the connection between HTML and JavaScript

HTML:                          JavaScript key:
─────────────────────────────────────────────
<button class="btn">          'btn'
<button class="btn primary">  'btn'    ← matches! (has "btn" among its classes)
<button class="submit">       ❌        ← no match (different class)

When you write 'btn' as a key, you are asking: "Find every element where class contains the word btn."

Before and After

BEFORE (3 active buttons):
┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│   Save       │  │   Cancel     │  │   Delete     │
│  [clickable] │  │  [clickable] │  │  [clickable] │
└──────────────┘  └──────────────┘  └──────────────┘

After: 'btn': { disabled: true }

AFTER (3 disabled buttons):
┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│   Save       │  │   Cancel     │  │   Delete     │
│  [disabled]  │  │  [disabled]  │  │  [disabled]  │
└──────────────┘  └──────────────┘  └──────────────┘

One line of code. Every button with class="btn" disabled simultaneously.

The shorthand and explicit forms

You can write this line in two ways that do the exact same thing:

javascript
// Shorthand — class is the default
'btn': { disabled: true }

// Explicit — spells out "class:" prefix
'class:btn': { disabled: true }

Both are correct. The shorthand is more concise. The explicit form makes the intent unmistakable. Use whichever feels clearer in your context.


Line 2: Tag Collections

javascript
'tag:p': { style: { lineHeight: '1.6' } }

What does this line say?

In plain English: "Find every <p> element on the page and set its line spacing to 1.6."

Breaking down the key

'tag:p'
  │   │
  │   └── The HTML tag name you are targeting
  └────── The 'tag:' prefix tells Collections.update():
          "I want ALL elements of this tag type"

The tag: prefix changes the matching rule entirely. Instead of looking for a class attribute, the library now looks for elements by their HTML tag type — every <p>, every <button>, every <img>, whatever tag you specify.

Reading the connection between HTML and JavaScript

HTML:                                JavaScript key:
─────────────────────────────────────────────────────
<p>First paragraph.</p>              'tag:p'  ← matched
<p class="intro">Second.</p>         'tag:p'  ← also matched (tag wins)
<p id="conclusion">Third.</p>        'tag:p'  ← also matched
<div>A div element</div>             ❌        ← NOT matched (wrong tag)

Tag targeting is inclusive: it matches all elements of that tag, regardless of their classes or IDs.

What is lineHeight?

lineHeight is the CSS property for the space between lines of text — like the "line spacing" control in a word processor.

BEFORE (tight spacing):
─────────────────────────────
This paragraph has default
line spacing. The text feels
cramped when paragraphs are
long or dense.
─────────────────────────────

AFTER { lineHeight: '1.6' }:
─────────────────────────────
This paragraph now has 1.6x

line spacing. Each line has

more breathing room, making

it easier to read.
─────────────────────────────

Common tag targets in real projects

javascript
Collections.update({
  'tag:button':   { disabled: false },          // all <button> elements
  'tag:input':    { disabled: true },           // all <input> elements
  'tag:a':        { style: { color: '#3b82f6' } },  // all <a> link elements
  'tag:img':      { setAttribute: { loading: 'lazy' } },  // all images
  'tag:textarea': { disabled: true }            // all <textarea> elements
});

Line 3: Name Attribute Collections

javascript
'name:email': { placeholder: 'Enter your email' }

What does this line say?

In plain English: "Find every form element that has name="email" and add placeholder hint text."

Breaking down the key

'name:email'
  │     │
  │     └── The value of the name attribute you are matching
  └──────── The 'name:' prefix tells Collections.update():
            "Match by the name attribute, not by class or tag"

Reading the connection between HTML and JavaScript

HTML:                                         JavaScript key:
──────────────────────────────────────────────────────────────
<input type="text" name="email">              'name:email' ← matched
<input type="email" name="email">             'name:email' ← also matched
<input type="email" name="billing-email">     ❌            ← different name
<input type="text" name="username">           ❌            ← different name

The type attribute does not matter for name-based matching. Only the name attribute value matters.

Why do form elements have a name attribute?

When a form is submitted, the browser bundles each field's value with its name to send to the server:

Submitted data:  email=alice@example.com&username=alice&password=...
                 ─────                   ────────        ────────
                   │                        │               │
              name="email"           name="username"  name="password"

The name attribute is how the server identifies which piece of data belongs to which field.

The real power: Multiple forms, one update

This is where 'name:email' becomes especially useful. When you have several forms on the same page:

html
<!-- Login form -->
<form id="login">
  <input type="text" name="email">
</form>

<!-- Newsletter signup -->
<form id="newsletter">
  <input type="email" name="email">
</form>

<!-- Contact form -->
<form id="contact">
  <input type="text" name="email">
</form>

One update touches all three:

javascript
Collections.update({
  'name:email': {
    placeholder: 'your.email@example.com',
    required: true
  }
});
BEFORE:
┌──────────────────┐   ┌──────────────────┐   ┌──────────────────┐
│                  │   │                  │   │                  │
│  (empty)         │   │  (empty)         │   │  (empty)         │
└──────────────────┘   └──────────────────┘   └──────────────────┘
   Login form             Newsletter form          Contact form

AFTER:
┌──────────────────┐   ┌──────────────────┐   ┌──────────────────┐
│ your.email@...   │   │ your.email@...   │   │ your.email@...   │
│ (required)       │   │ (required)       │   │ (required)       │
└──────────────────┘   └──────────────────┘   └──────────────────┘
   Login form             Newsletter form          Contact form

All three email inputs updated from a single call.


Reading the Whole Example Together

Now that you understand each line, let's read the complete example:

javascript
Collections.update({
  'btn': { disabled: true },
  'tag:p': { style: { lineHeight: '1.6' } },
  'name:email': { placeholder: 'Enter your email' }
});

Reading it like a sentence:

"Disable every element with class btn. Set line spacing to 1.6 on every paragraph element. Add the placeholder 'Enter your email' to every input named email."

Translation table:

KeyWhat it meansWhat it targets
'btn'class="btn" (shorthand)Every element wearing the btn class
'tag:p'all <p> elementsEvery paragraph tag on the page
'name:email'name="email"Every form input with that name value

Visual summary of which elements get touched:

Your HTML page:
┌─────────────────────────────────────────────────────┐
│  <button class="btn">Save</button>       ←─ 'btn'   │
│  <button class="btn">Cancel</button>     ←─ 'btn'   │
│  <button class="btn">Delete</button>     ←─ 'btn'   │
│                                                     │
│  <p>First paragraph...</p>           ←─ 'tag:p'     │
│  <p>Second paragraph...</p>          ←─ 'tag:p'     │
│  <p>Third paragraph...</p>           ←─ 'tag:p'     │
│                                                     │
│  <input name="email">                ←─ 'name:email'│
│  <input name="email">                ←─ 'name:email'│
│  <input name="username">             ✗ (not matched)│
└─────────────────────────────────────────────────────┘

Reading the Code Out Loud

One reliable technique for understanding any Collections.update() call is to read it like instructions in English. Here's a pattern that works:

'[collection key]': { [update] }

Read as:
"For every [what the key describes], apply [the update]."

Practice:

javascript
'card':          { style: { opacity: '0.5' } }
// "For every element with class 'card', set opacity to 0.5"

'tag:button':    { disabled: true }
// "For every <button> element, disable it"

'name:phone':    { placeholder: '+1 (555) 000-0000' }
// "For every element with name='phone', add a placeholder"

'class:alert':   { classList: { add: 'visible' } }
// "For every element with class 'alert', add the 'visible' class"

Once you can read the code aloud fluently, you can also write it fluently.


Common Beginner Mistakes

Mistake 1: Using CSS dot syntax for classes

javascript
// ❌ WRONG — the dot means nothing here, this looks for class="."
Collections.update({
  '.btn': { disabled: true }
});

// ✅ CORRECT — just the class name, no dot
Collections.update({
  'btn': { disabled: true }
});

Collections.update() is not CSS. The . prefix is a CSS selector convention. Here, you write the class name directly.

The fix: Remove the dot.


Mistake 2: Forgetting 'tag:' when targeting by HTML tag

javascript
// ❌ WRONG — 'p' is treated as a class name, looks for class="p"
Collections.update({
  'p': { style: { lineHeight: '1.6' } }
});

// ✅ CORRECT — 'tag:p' explicitly means the <p> tag
Collections.update({
  'tag:p': { style: { lineHeight: '1.6' } }
});

Without the tag: prefix, 'p' just means "find elements with class="p"" — which is almost certainly not what you want.

The fix: Add tag: before any HTML tag name.


Mistake 3: Confusing name collections with class collections

javascript
// These look similar but target entirely different elements:

'submit': { disabled: true }
// ← Targets elements with CLASS "submit"
// Matches: <button class="submit">

'name:submit': { disabled: true }
// ← Targets elements with NAME attribute "submit"
// Matches: <button name="submit">

The difference is subtle in the code but significant in the DOM.

The fix: If you want the name attribute, always include name:. If you want a class, write just the name.


Mistake 4: Expecting per-element variation

javascript
// ❌ This does NOT set different text per button
Collections.update({
  'btn': { textContent: 'Click Me' }
});
// Every button will say "Click Me" — not unique per button

Collections.update() applies the same update object to every element in the group. For per-element differences, use Elements.update():

javascript
// ✅ Different text per button
Elements.update({
  saveBtn:   { textContent: 'Save' },
  cancelBtn: { textContent: 'Cancel' },
  deleteBtn: { textContent: 'Delete' }
});

The Format Cheat Sheet

Keep this handy:

Format          Targets                        Example
──────────────────────────────────────────────────────────
'name'          Elements with class="name"     'btn'
'class:name'    Elements with class="name"     'class:btn'
'tag:name'      All elements of that tag       'tag:p'
'name:value'    Elements with name="value"     'name:email'

Key Takeaways

  1. Three-layer structure: method call → bulk object → update objects
  2. No prefix = class by default. 'btn' means class="btn".
  3. tag: prefix = target by HTML tag type. 'tag:p' matches all <p> elements.
  4. name: prefix = target by name attribute. 'name:email' matches name="email".
  5. No CSS dot syntax. Write 'btn', not '.btn'.
  6. Same update object goes to every element in the collection.
  7. Read it aloud: "For every [collection], apply [update]."

Up next: A full deep dive into the type:value format — all four forms, all the edge cases, and the mental models to make it stick.