Lesson 7 — Composing views from components
The boards index already composes EmptyState and the board card.
This lesson looks at composition more deliberately — how to decide when
to extract a component, how to pass data through a composition chain,
and how to keep views readable as complexity grows.
When to extract a component
The board card in Views::Boards::Index is currently a private method:
|
|
When should this become Components::BoardCard? Ask:
- Is it reused? If the board card appears in multiple views, extract it.
- Does it have meaningful variants? If the card needs a compact mode, an archived state, or a loading skeleton, extract it.
- Does it have testable logic? If the card makes decisions — show a badge if the board is archived, truncate the name at a certain length — extract it so that logic can be tested in isolation.
For now the board card is simple and appears in one place. Leave it as a private method. We will extract it in Module 9 when the board show page needs a more complex version.
Passing data through a composition chain
A view passes data to a component which passes data to a sub-component:
|
|
The data flows in one direction: view → component → sub-component. Each
level only knows about its own props — BoardCard knows about board,
Badge knows about label and variant. Neither knows about the other.
Keeping views readable
As views grow, private methods become the primary tool for keeping
view_template readable. The pattern we use throughout KanbanFlow:
view_templatereads like a table of contents — high-level structure only- Private
render_methods handle the detail of each section - Components handle anything with meaningful variants, logic, or reuse
|
|
This structure means any developer can open a view and immediately understand what it renders, before reading a single implementation detail.