
Interaction design patterns in Drupal Canvas
How Canvas handles interactions, what patterns scale, and what happens when an editor wants something Canvas doesn't support.
Canvas launched its interaction system three months ago, and it is genuinely sophisticated. An editor can declare that a card is clickable, that a hero has a parallax background, that an image opens a modal. The composition system orchestrates these without custom code. For universities that have been building interactions in JavaScript for years, this is foundational.
I have spent time in the Canvas interaction docs and in the beta implementations I can reach. The patterns that scale are clear. The boundaries where Canvas stops helping are also clear. Understanding where that boundary lives is the difference between a system that makes work faster and one that creates new constraints.
How Canvas thinks about interactions
Canvas separates concerns between components and composition. A component declares what interactions it supports. A modal card component has a built-in interaction handler for “open modal on click.” A parallax hero component declares “supports parallax scroll.” The composition layer connects editors to these declarations — an editor uses the Canvas UI to say “this card should open a modal.”
name: Cardinteractions: click: label: "Clickable card" handlers: - type: navigate label: "Navigate to URL" - type: modal label: "Open in modal" - type: none label: "Not clickable"This is powerful because the component declares what it can do, and the composition layer respects those boundaries. An editor cannot accidentally apply an interaction the component does not support. The markup stays clean because the interaction is a property of the component, not a mutation of it.
What scales well
Simple click-based interactions scale beautifully. Navigation, modal triggers, scroll-to-section, form submission — these are the interactions that happen most of the time in university sites. Canvas handles them without requiring custom code. An editor can click through the Canvas UI and build a page that would have taken a developer half a day in JavaScript.
The accessibility here is done well. Canvas generates proper ARIA attributes, announces state changes to screen readers, and ensures keyboard navigation works. This is not a small thing. Many custom interaction systems get accessibility wrong. Canvas got it right.
Scroll-based interactions also work well — parallax, fade on scroll, reveal on scroll. These are visual enhancements, not structural. Canvas implements them performantly without layout thrashing. An editor can compose a hero with a parallax background in the UI instead of asking a developer to implement it.
Where the boundary shows up
The first place I hit the boundary was with conditional interactions. A card’s interaction depends on content — if there is an event date in the past, the card should not be clickable; if the date is future, it should navigate to the event. Canvas does not support conditional interactions. The interaction is static once it is set up.
This is an honest limitation. Implementing conditional interactions in the composition layer would require logic that goes beyond “respond to user input.” Canvas is built for editor-driven composition, not for rule-driven logic. If you need conditional interactions, that is back to custom code.
The second boundary is with multi-step interactions. Some university sites have a card that shows a teaser on hover, then opens a modal on click, then shows a form in the modal. Canvas can compose this, but each step is a separate interaction. The teaser-on-hover is a CSS state. The modal-on-click is a Canvas interaction. The form is HTML. They work together, but you are thinking about them as separate systems.
The third boundary is with data-driven interactions. An interaction that changes based on the user’s state — “only clickable if you are logged in,” or “navigate to a different URL depending on your role” — is beyond Canvas. The composition layer assumes all users get the same interaction pattern.
How I think about solving these
Conditional interactions are a signal that you need custom logic. Build it as a custom component, not as Canvas interaction. A component that wraps a card and decides whether to render it as clickable or static is cleaner than trying to add conditions to Canvas.
public function render($node) { $isClickable = $this->isEventFuture($node);
return [ 'card' => $this->buildCard($node), 'interaction' => $isClickable ? 'navigate' : null, ];}Multi-step interactions work well if you separate them. The teaser-on-hover is CSS. The modal is a Canvas interaction. The form is a component inside the modal. Each thing does its job. The separation is honest.
Data-driven interactions are trickier. The honest answer is often that the composition layer cannot handle them. If an interaction needs to know the user’s role to decide its behavior, that decision happens in the component, not in Canvas. The component renders the appropriate interaction. Canvas just makes it visible and orchestrates it.
What I still haven’t solved
The one thing that bugs me is the story around progressive enhancement. Canvas generates a bunch of JavaScript to make interactions work. That JavaScript runs and handles clicks, scroll, all of it. If someone has JavaScript disabled, what happens?
Canvas generates functional HTML fallbacks for simple cases — a clickable card with navigation becomes a proper <a> tag. Modal interactions are trickier. An editor builds a “click to open modal” interaction, but without JavaScript, there is no modal. Canvas does not gracefully degrade here.
For universities, this might matter. Some students will have JavaScript disabled. Some will be on unstable connections. The platforms that get this right are the ones that treat Canvas interactions as enhancements, not requirements. The page should still be usable if Canvas interactions do not load.
I have not seen a robust pattern for this yet. Canvas is still young. I am watching to see whether the community converges on one.
How this changes component design
The bigger implication is that components are about to become more prescriptive. In the current Drupal, a component is primarily about markup and styling. Canvas adds a layer where components declare their supported interactions. This is good — it makes capabilities explicit. It also means you cannot build a component that “supports any interaction.” You have to declare the ones it actually supports.
For a component library, this is the moment to think hard about what interactions matter. Not every component needs to be clickable. Not every component needs scroll interactions. Declaring what a component actually supports makes the library more robust, not less.
Canvas arrived at the right time for the Drupal ecosystem. The community understands components well enough now to use Canvas effectively. The platforms that will thrive are the ones that use it as a tool for composition, not as a replacement for thoughtful component design.
What this came from
- ArticleCanvas interaction API