# Canvas Component Utils

> Use utility components to render formatted text and media correctly. Use when (1) Rendering HTML text content from props, (2) Displaying images, (3) Working with formatted text or media. Covers FormattedText and Image utilities.

- Skill: `drupal-canvas/canvas-component-utils` (Agent Skill)
- Install (CLI): `npx skillmds@latest add drupal-canvas/canvas-component-utils`
- Raw SKILL.md: https://api.skillmd.com/api/skills/drupal-canvas/canvas-component-utils/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: drupal-canvas (https://skillmd.com/u/drupal-canvas)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/drupal-canvas/canvas-component-utils

---


## Project type

Before applying this skill, check `package.json` for a dependency named
`@drupal-canvas/headless` or starting with `@drupal-canvas/headless-`. If one is
present, this is a Canvas Headless codebase and **this skill does not apply**:
the `drupal-canvas` package is not supported there. Use the framework-native
alternatives in [`canvas-headless`](../canvas-headless/SKILL.md) instead
(HTML-injection primitives for formatted text, plain `<img>` for images). If no
such dependency is present, this is a Canvas-rendered React codebase: components
are React (`index.jsx`/`.tsx`) and everything in this skill applies as written.
These are the only two project types.

Import utilities from the `drupal-canvas` package:

```jsx
import { FormattedText, Image } from 'drupal-canvas';
```

## FormattedText

Use `FormattedText` to render HTML content from props. This is required for any
prop with `contentMediaType: text/html` in component.yml.

```yaml
# component.yml
props:
  properties:
    text:
      title: Text
      type: string
      contentMediaType: text/html
      x-formatting-context: block
      examples:
        - <p>This is <strong>formatted</strong> text.</p>
```

```jsx
import { FormattedText } from 'drupal-canvas';

const Text = ({ text, className }) => (
  <FormattedText className={className}>{text}</FormattedText>
);
```

**When to use FormattedText:**

- Props that accept rich text/HTML content
- Any prop with `contentMediaType: text/html`
- Content that may contain `<p>`, `<strong>`, `<em>`, `<a>`, or other HTML tags

**Do NOT use FormattedText for:**

- Plain text props (type: string without contentMediaType)
- Headings or titles (use regular elements)

## Image

Use `Image` for responsive image rendering. It handles responsive behavior and
optimization automatically. The component contract should accept a single image
object prop that matches `$ref: json-schema-definitions://canvas.module/image`;
do not split that data into separate `imageUrl`/`imageAlt` props.

```yaml
# component.yml
props:
  properties:
    image:
      title: Image
      type: object
      $ref: json-schema-definitions://canvas.module/image
      examples:
        - src: https://example.com/photo.jpg
          alt: Description of image
          width: 800
          height: 600
```

```jsx
import { Image } from 'drupal-canvas';

const Card = ({ image }) => {
  if (!image?.src) return null;

  const { src, alt, width, height } = image;
  return (
    <Image
      src={src}
      alt={alt}
      width={width}
      height={height}
      className="w-full rounded-lg object-cover"
    />
  );
};
```

**Image props:**

- `src` - Image URL (required)
- `alt` - Alt text for accessibility (required)
- `width` - Original image width
- `height` - Original image height
- `className` - Tailwind classes for styling

