Course outline
Modules and lessons joined by lines that stay attached while modules open, lessons get ticked off and finished work drops away.
Course
Product Design Foundations
Every course platform, creator site and onboarding flow has an outline like this. Here the lines from each module to its lessons are redrawn on every frame of the animation, so they bend and stretch with the rows instead of jumping when something opens, closes or drops away.
Things to try
- Open and close modules. The lessons slide out of the way and the lines grow and retract with them.
- Tick a lesson off. The circle becomes a tick, the module's count and the progress bar update, and "Up next" moves on. Finish every lesson in a module and its number fills in.
- Show only what's remaining. Finished lessons leave, their lines drawing back out, and the rest close up. A finished module disappears entirely.
- Use the keyboard. Up and down move through the outline; right opens a module, left closes it or goes up to it.
Install
npx shadcn@latest add https://your-docs-site/r/course-outline.jsonDependencies
The install command adds these for you. If you copy the code by hand, install them yourself.
npm install @base-ui/react @hugeicons/core-free-icons @hugeicons/react @remold-ui/react motionHow it works
Each module's number carries data-rm-anchor with the module's id, and each lesson's tick carries data-rm-link with its module's id. Connectors draws a line from every anchor to everything that links to it. Motion owns the rows' layout animation, while useConnectorMotion keeps those lines attached during the transition.
const connectorRef = useRef<HTMLDivElement>(null);
const connectorMotion = useConnectorMotion(connectorRef);
<Remold.Connectors ref={connectorRef} radius={10}>
<motion.div layout {...connectorMotion}>
{rows.map((row) =>
row.module ? (
<motion.button layout {...connectorMotion} key={row.id}>
<Module number={<span data-rm-anchor={row.id}>{row.n}</span>} />
</motion.button>
) : (
<motion.div layout {...connectorMotion} key={row.id}>
<Lesson tick={<button data-rm-anchor={row.id} data-rm-link={row.parent} />} />
</motion.div>
),
)}
</motion.div>
</Remold.Connectors>Comment thread
A post and the conversation under it: typing that grows into the reply, lines that light the path to it, and replies that fold away and come back.
Currency converter
A converter at today's real exchange rates: type what you send and what they get rolls with it, tap a currency and the whole card springs into a searchable list, and Send says what it did.