Lesson 3 — Component communication¶
Objective¶
Design reusable components with small typed APIs and explicit state ownership.
Prerequisites¶
Signals, template bindings, events, and stable collection identity at a working level.
Mental model¶
Data normally flows down through inputs and domain events flow up through outputs. The component owning a business decision changes source state. Projection supplies optional structure without transferring ownership.
Why it exists¶
Explicit contracts make components composable, testable, and resistant to invalid combinations. Domain events communicate intent better than leaking browser events.
Working model: parent passes input; child emits output.
Engineering reality: ownership follows the business invariant, not necessarily the visual tree. Two-way binding is input/output syntax and can hide that decision.
Minimal example¶
readonly value = input.required<number>();
readonly degrees = computed(() => `${clamp(this.value()) * 3.6}deg`);
readonly statusChange = output<TopicStatus>();
Real-world usage¶
Design-system controls, feature cards, tables, and forms need APIs that express valid states while leaving domain transitions with the correct owner.
Common mistakes¶
- injecting a global store into every reusable child;
- emitting raw
clickwhen consumers needstatusChange; - exposing many coupled boolean inputs;
- allowing visual and accessible values to diverge;
- using
model()where ownership is not genuinely shared editing.
Mini lab¶
Task: Extract an accessible ProgressRingComponent with required signal input and computed presentation. Create TopicCardComponent with typed topic input, status output, and optional projected actions. Keep store mutation in the feature parent.
Constraints: clamp 0–100, expose progressbar name/min/max/value, and do not inject the tracker store into reusable cards.
Expected result: visual and ARIA progress agree; a card event causes the parent to update source state.
Hint 1
Put presentation derivation in the child and business transitions in the owner.
Hint 2
Replace boolean combinations with semantic variants, projected content, or separate components.
Solution direction — last resort
Use required signal inputs, a computed clamped angle, and a typed domain output. Let TopicsComponent invoke the store.
Verification¶
Test values below 0, 42, and above 100 through the public API and accessible DOM. Propose a replacement for 14 visual boolean inputs and identify impossible combinations.
Mastery evidence: design a compact API, locate source-state ownership, and prove the child does not perform the domain transition.
Bloom challenge¶
- Understand: signal input versus mutable decorated field.
- Apply: emit a typed domain event.
- Analyze: identify ownership hidden by two-way binding.
- Evaluate: projection, template fragments, or separate variants.
- Create: design a reusable card contract that prevents invalid combinations.
Summary¶
Good component boundaries communicate values and intent while keeping invariants with an explicit owner.
Spaced review¶
In Lesson 4, classify child presentation as derived or source state. In Lesson 10, test this contract without private implementation assertions.
What comes next¶
Continue to signals and state.