# 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. We’ll end up with a `` 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`: ```javascript import "./hello-world.js"; describe(" (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 Lit’s 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: ```bash npm test ``` All tests should fail — we haven’t 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: ```javascript 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`
Hello, ${this.name}!
`; } _onClick() { alert(`Hello, ${this.name}!`); } } customElements.define("hello-world", HelloWorld); ``` Run the tests again: ```bash npm test ``` ✅ All should now pass. --- ## ⚡ 4. Step 3 — Try it live Edit `src/index.html` to demonstrate both variants: ```html ``` Then: ```bash npm run dev ``` In the browser you’ll see: ``` Hello, World! Hello, Coulomb! ``` and both are clickable. --- ## 🔄 5. Step 4 — Live updates (optional exploration) Open the browser console and type: ```javascript document.querySelector("hello-world").name = "Agent"; ``` The first greeting should **update instantly** to: ``` Hello, Agent! ``` That’s Lit’s reactive update mechanism at work. --- ## 🧭 6. Step 5 — Visual story (optional) `src/components/hello-world/hello-world.stories.js` ```javascript import "./hello-world.js"; export default { title: "UI/Hello World (Reactive)" }; export const Default = () => ``; export const CustomName = () => ``; ``` 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 `` that updates the `name` property live when the user types. xxx