Files
testdrive-jsui/tutorials/Tutorial 2 Reactive Properties.md

4.7 KiB
Raw Blame History

Tutorial 2 Reactive Properties

This second TestDrive-UI tutorial extends your previous hello-world component by introducing reactive properties (i.e., component inputs) and dynamic rendering, all under TDD control.

Well end up with a <hello-world name="Kale"></hello-world> component that greets a given name — and can change dynamically when the property updates.


🧭 1. Goal

The component should display “Hello, [name]!” and automatically update when the name property changes.

If no name is given, it should default to “World”.


🧪 2. Step 1 — Write the failing test first

Create src/components/hello-world/hello-world.props.test.js:

import "./hello-world.js";

describe("<hello-world> (with name property)", () => {
  it("renders default greeting when no name is set", () => {
    const el = document.createElement("hello-world");
    document.body.appendChild(el);

    const text = el.shadowRoot.textContent.trim();
    expect(text).to.equal("Hello, World!");
  });

  it("renders custom greeting when name is set", async () => {
    const el = document.createElement("hello-world");
    document.body.appendChild(el);
    el.name = "Kale";

    // Wait for Lits update cycle
    await el.updateComplete;

    const text = el.shadowRoot.textContent.trim();
    expect(text).to.equal("Hello, Kale!");
  });

  it("reacts to property change after initial render", async () => {
    const el = document.createElement("hello-world");
    document.body.appendChild(el);
    el.name = "Aria";
    await el.updateComplete;

    let text = el.shadowRoot.textContent.trim();
    expect(text).to.equal("Hello, Aria!");

    el.name = "Nova";
    await el.updateComplete;

    text = el.shadowRoot.textContent.trim();
    expect(text).to.equal("Hello, Nova!");
  });
});

Run:

npm test

All tests should fail — we havent implemented anything yet.


🧩 3. Step 2 — Implement the feature

Open your existing src/components/hello-world/hello-world.js and replace the class with this improved version:

import { LitElement, html, css } from "lit";

export class HelloWorld extends LitElement {
  static properties = {
    name: { type: String }
  };

  constructor() {
    super();
    this.name = "World";
  }

  static styles = css`
    div {
      font-family: system-ui, sans-serif;
      font-size: 1.5rem;
      color: #007acc;
      padding: 1rem;
      text-align: center;
      cursor: pointer;
      user-select: none;
    }
    div:hover {
      color: #005fa3;
    }
  `;

  render() {
    return html`<div @click=${this._onClick}>
      Hello, ${this.name}!
    </div>`;
  }

  _onClick() {
    alert(`Hello, ${this.name}!`);
  }
}

customElements.define("hello-world", HelloWorld);

Run the tests again:

npm test

All should now pass.


4. Step 3 — Try it live

Edit src/index.html to demonstrate both variants:

<hello-world></hello-world>
<hello-world name="Coulomb"></hello-world>

Then:

npm run dev

In the browser youll see:

Hello, World!
Hello, Coulomb!

and both are clickable.


🔄 5. Step 4 — Live updates (optional exploration)

Open the browser console and type:

document.querySelector("hello-world").name = "Agent";

The first greeting should update instantly to:

Hello, Agent!

Thats Lits reactive update mechanism at work.


🧭 6. Step 5 — Visual story (optional)

src/components/hello-world/hello-world.stories.js

import "./hello-world.js";

export default {
  title: "UI/Hello World (Reactive)"
};

export const Default = () => `<hello-world></hello-world>`;
export const CustomName = () => `<hello-world name="Bernd"></hello-world>`;

If Storybook is later installed, these stories will become live demos.


🧩 7. Key Takeaways

Concept Explanation
Reactive property Declared via static properties = { ... } in Lit
Default values Set in the constructor
Automatic updates Changing the property triggers re-render
Testing updates Use await el.updateComplete before asserting

🧪 8. What you learned

  • How to declare reactive component properties
  • How to test reactivity with Mocha + jsdom
  • How to update and verify UI behavior in a TDD loop

Next, we can take it one level further:

Add a text input inside <hello-world> that updates the name property live when the user types.

xxx