Code components - Using packages
Importing packages
Section titled “Importing packages”Although a number of useful built-in and bundled packages are provided, you can also import any npm package through the web.
import { motion } from 'https://esm.sh/motion@12.23.26/react?external=react,react-dom';esm.sh unwraps all dependencies of the package you import as
additional import statements. When importing packages that would normally import
e.g. react or react-dom themselves, esm.sh can skip returning import
statements for those packages by appending the URL with ?external. This is
important to avoid running multiple versions of React.
Built-in custom packages
Section titled “Built-in custom packages”drupal-canvas
Section titled “drupal-canvas”The drupal-canvas package provides utilities and base components for building code components.
FormattedText
Section titled “FormattedText”Source Code
A built-in component to render text with trusted HTML using dangerouslySetInnerHTML.
The content is safe when processed through Drupal’s filter system that is correctly configured.
import { FormattedText } from 'drupal-canvas';
export default function Example() { return ( <FormattedText> <em>Hello, world!</em> </FormattedText> );}Source Code
Utility for combining Tailwind CSS classes.
import { cn } from 'drupal-canvas';
export default function Example() { return <ControlDots className="top-4 left-4 stroke-white absolute" />;}
const ControlDots = ({ className }) => ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 31 9" fill="none" strokeWidth="2" className={cn('w-12', className)} > <ellipse cx="4.13" cy="4.97" rx="3.13" ry="2.97" /> <ellipse cx="15.16" cy="4.97" rx="3.13" ry="2.97" /> <ellipse cx="26.19" cy="4.97" rx="3.13" ry="2.97" /> </svg>);Utilities for working with JSON:API
Section titled “Utilities for working with JSON:API”See data fetching
Bundled npm packages
Section titled “Bundled npm packages”Tailwind
Section titled “Tailwind”tailwindcss.com
Tailwind 4 is available to all components by default. The global CSS is added to
all pages with the @import "tailwindcss" directive included.
You can use the @theme directive to customize theme variables.
For example, you can add a new color to your project by defining a theme
variable like --color-drupal-blue:
@theme { --color-drupal-blue: #009cde;}Now you can use utility classes like bg-drupal-blue, text-drupal-blue, or
fill-drupal-blue in your component markup:
export default function Example() { return <div className="bg-drupal-blue">Drupal Blue</div>;}GitHub Project Page
A tiny utility for constructing className strings conditionally.
Also serves as a faster & smaller drop-in replacement for the classnames module.
import { clsx } from 'clsx'
export default function Example() { return ( <div className={clsx('foo', true && 'bar', 'baz');} /> // => 'foo bar baz' );};class-variance-authority
Section titled “class-variance-authority”GitHub Project Page
CVA helps you define components with multiple visual variants (like size, color, state) in a clean, type-safe way. Instead of manually concatenating CSS classes or writing complex conditional logic, you define variants upfront and let CVA handle the class composition.
import { cva } from 'class-variance-authority';
const button = cva( 'font-semibold border rounded', // base classes { variants: { intent: { primary: 'bg-blue-500 text-white border-blue-500', secondary: 'bg-gray-200 text-gray-900 border-gray-200', }, size: { small: 'text-sm py-1 px-2', medium: 'text-base py-2 px-4', }, }, defaultVariants: { intent: 'primary', size: 'medium', }, },);
// Usagebutton({ intent: 'secondary', size: 'small' });// Returns: "font-semibold border rounded bg-gray-200 text-gray-900 border-gray-200 text-sm py-1 px-2"@drupal-api-client/json-api-client and drupal-jsonapi-params
Section titled “@drupal-api-client/json-api-client and drupal-jsonapi-params”See data fetching
See data fetching
@tailwindcss/typography
Section titled “@tailwindcss/typography”GitHub Project Page
The @tailwindcss/typography
plugin adds a set of prose classes that apply beautiful typographic defaults
to vanilla HTML — perfect for rendering rich text from Drupal’s text fields
using the FormattedText component.
To enable the plugin, add the @plugin directive to your Global CSS:
@plugin "@tailwindcss/typography";Then use the prose class on a FormattedText component to style the rendered
HTML content:
import { FormattedText } from 'drupal-canvas';
export default function Article({ body }) { return ( <FormattedText className="prose lg:prose-xl" as="div"> {body} </FormattedText> );}Size modifiers
Section titled “Size modifiers”Control the overall font size of prose content with size modifiers:
prose-sm— Smaller text (14px)prose-base— Default size (16px)prose-lg— Larger text (18px)prose-xl— Extra large (20px)prose-2xl— Largest (24px)
These can be combined with responsive prefixes:
<FormattedText className="prose md:prose-lg lg:prose-xl"> {body}</FormattedText>Dark mode
Section titled “Dark mode”Use prose-invert to switch to an inverted color palette for dark backgrounds:
<FormattedText className="prose dark:prose-invert"> {body}</FormattedText>Element modifiers
Section titled “Element modifiers”Override styles for specific HTML elements inside prose content using
prose-{element}:{utility} modifiers:
See the Element modifiers documentation for the full element list and examples.
<FormattedText className="prose prose-headings:underline prose-a:text-blue-600 prose-img:rounded-xl"> {body}</FormattedText>Undoing prose styles
Section titled “Undoing prose styles”Use the not-prose class to exclude a block from prose styling:
<article className="prose"> <h1>My Heading</h1> <div className="not-prose"> {/* This content is not affected by prose styles. */} </div></article>Removing the max-width
Section titled “Removing the max-width”Each prose size includes a built-in max-width. Add max-w-none to let
content fill its container:
<FormattedText className="prose max-w-none"> {body}</FormattedText>tailwind-merge
Section titled “tailwind-merge”GitHub Project Page
A utility function to efficiently merge Tailwind CSS classes in JS without style conflicts.
import { twMerge } from 'tailwind-merge';
twMerge('px-2 py-1 bg-red hover:bg-dark-red', 'p-3 bg-[#B91C1C]');// → 'hover:bg-dark-red p-3 bg-[#B91C1C]'