### Install Workbench
Source: https://project.pages.drupalcode.org/canvas/code-components/workbench
Install Workbench using npm. After installation, you can run it from your project root.
```bash
npm install @drupal-canvas/workbench
```
```bash
npx canvas-workbench
```
--------------------------------
### Example: Index-style component file structure
Source: https://project.pages.drupalcode.org/canvas/code-components/workbench/mocks
Illustrates the placement of the mocks.json file for an index-style component.
```text
src/components/hero/
index.tsx
component.yml
mocks.json
```
--------------------------------
### Example: Named component file structure
Source: https://project.pages.drupalcode.org/canvas/code-components/workbench/mocks
Illustrates the placement of the [component-name].mocks.json file for a named component.
```text
src/components/
card.tsx
card.component.yml
card.mocks.json
```
--------------------------------
### Set Default Prop Values
Source: https://project.pages.drupalcode.org/canvas/sdc-components/validations
Use the 'examples' property to set default values for props. The first item in the 'examples' array is used as the default. 'examples' must be an array, and is mandatory when a prop is required.
```yaml
props:
type: object
text:
type: string
examples:
- "Hot"
- "New"
description: "The text displayed in the badge."
```
--------------------------------
### SDC Component Structure Example
Source: https://project.pages.drupalcode.org/canvas/sdc-components
Illustrates the typical file structure for a Single Directory Component within a Drupal theme.
```yaml
my_theme/
└── components/
└── singer/
├── singer.component.yml
├── singer.twig
├── singer.css
└── micro.jpg
```
--------------------------------
### Example Page JSON
Source: https://project.pages.drupalcode.org/canvas/code-components/workbench/pages
This JSON defines the structure and content for a page preview in Workbench. It includes a title and a tree of elements, each with a type, props, and slots.
```json
{
"title": "Home",
"elements": {
"header": {
"type": "js.header",
"props": {
"darkVariant": true,
"backgroundColor": "crust"
},
"slots": {
"branding": ["header-logo"],
"navigation": ["header-navigation"]
}
},
"header-logo": {
"type": "js.logo",
"props": {
"linkToFrontPage": true
}
},
"header-navigation": {
"type": "js.navigation",
"props": {}
},
"card-grid": {
"type": "grid",
"props": {
"columns": 3,
"gap": "md"
},
"slots": {
"items": ["card-1", "card-2", "card-3"]
}
},
"card-1": {
"type": "card",
"props": {
"featured": true
},
"slots": {
"header": ["card-1-header"],
"content": ["card-1-content"],
"footer": ["card-1-footer"]
}
},
"card-1-header": {
"type": "heading",
"props": {
"text": "Featured article"
}
},
"card-1-content": {
"type": "text",
"props": {
"content": "Learn how editorial teams use Canvas to review, refine, and publish AI-assisted content."
}
},
"card-1-footer": {
"type": "button-group",
"slots": {
"items": ["card-1-primary-action", "card-1-secondary-action"]
}
},
"card-1-primary-action": {
"type": "button",
"props": {
"label": "Read more",
"href": "/articles/canvas-workflows"
}
},
"card-1-secondary-action": {
"type": "button",
"props": {
"label": "Save for later",
"href": "/saved"
}
},
"card-2": {
"type": "card",
"props": {
"featured": false
},
"slots": {
"header": ["card-2-header"],
"content": ["card-2-content"],
"footer": ["card-2-footer"]
}
},
"card-2-header": {
"type": "heading",
"props": {
"text": "Documentation update"
}
},
"card-2-content": {
"type": "text",
"props": {
"content": "Review the latest guidance for authoring Workbench component mocks."
}
},
"card-2-footer": {
"type": "button",
"props": {
"label": "Open docs",
"href": "/docs/workbench-mocks"
}
},
"card-3": {
"type": "card",
"props": {
"featured": false
},
"slots": {
"header": ["card-3-header"],
"content": ["card-3-content"],
"footer": ["card-3-footer"]
}
},
"card-3-header": {
"type": "heading",
"props": {
"text": "Team workflow"
}
},
"card-3-content": {
"type": "text",
"props": {
"content": "Coordinate AI drafting, editorial review, and publishing approvals in one place."
}
},
"card-3-footer": {
"type": "button",
"props": {
"label": "See workflow",
"href": "/workflow"
}
}
}
}
```
--------------------------------
### Page File Structure
Source: https://project.pages.drupalcode.org/canvas/code-components/workbench/pages
Example of a page file structure for Workbench. Place page files in the top-level `pages` directory. Workbench discovers `pages/*.json` files.
```json
pages/
home.json
about.json
```
--------------------------------
### Define a React Component with Props
Source: https://project.pages.drupalcode.org/canvas/code-components/props
This example shows a basic React component that accepts a 'firstName' prop and renders a greeting. Props are destructured directly in the function signature.
```javascript
const Hello = ({ firstName }) => {
return
Hello, {firstName}!
;
};
export default Hello;
```
--------------------------------
### Get site branding data
Source: https://project.pages.drupalcode.org/canvas/code-components/data-fetching
Access site branding information, such as the site name, using the getSiteData utility.
```javascript
import { getSiteData } from 'drupal-canvas';
const { siteName } = getSiteData().branding;
```
--------------------------------
### Define Card Slots with Descriptions
Source: https://project.pages.drupalcode.org/canvas/ai-assistant
Use this YAML structure to define slots for a card component. Explicitly describe the intended content for each slot, like 'content' for text and 'actions' for buttons, to guide the AI.
```yaml
slots:
content:
title: Card Description
description: >
The description or body text of the card.
Don't place buttons or badges here, use the actions slot for that.
actions:
title: Actions
description: The actions of the card, use buttons or badge components here.
```
--------------------------------
### Get page data
Source: https://project.pages.drupalcode.org/canvas/code-components/data-fetching
Access information about the current page, such as title, breadcrumbs, and the main entity, using the getPageData utility. Results are viewable in the Data Fetch pane.
```javascript
import { getPageData } from 'drupal-canvas';
const { pageTitle, breadcrumbs, mainEntity } = getPageData();
```
--------------------------------
### Run Workbench
Source: https://project.pages.drupalcode.org/canvas/code-components/workbench
Run Workbench from your project root using npx. This command initiates the local preview and development server.
```bash
npx @drupal-canvas/workbench@latest
```
--------------------------------
### Build Component Preview
Source: https://project.pages.drupalcode.org/canvas/code-components/workbench/preview-build
Use this command to export a standalone preview artifact for a specific component. Ensure the `--component-path` points to the component's YAML file and `--out-dir` specifies the desired output directory.
```bash
npx canvas-workbench preview-build --component-path components/card/component.yml --out-dir .canvas-preview/card
```
--------------------------------
### Create a Basic React Component
Source: https://project.pages.drupalcode.org/canvas/code-components
Define a new component with a default export. Ensure the component accepts props and renders JSX. This serves as a starter template for new components.
```javascript
const Component = ({ text = 'Component' }) => {
return
{text}
;
};
export default Component;
```
--------------------------------
### Build Page Preview
Source: https://project.pages.drupalcode.org/canvas/code-components/workbench/preview-build
Use this command to export a standalone preview artifact for a specific page. Ensure the `--page-path` points to the page's JSON file and `--out-dir` specifies the desired output directory.
```bash
npx canvas-workbench preview-build --page-path pages/home.json --out-dir .canvas-preview/home
```
--------------------------------
### Image Component with Sizes Prop
Source: https://project.pages.drupalcode.org/canvas/code-components/responsive-images
Configure the `sizes` prop to define image download sizes across different breakpoints. This impacts performance for images using `fill` or styled responsively.
```javascript
```
--------------------------------
### Advanced Mock Format for Workbench
Source: https://project.pages.drupalcode.org/canvas/code-components/workbench/mocks
Use the advanced format when the preview needs full control over the rendered root element. This format is useful when you need to render a component inside other components to verify how it behaves in context. It allows you to define the full element tree, including the root element and any elements referenced by slots.
```json
[
{
"name": "In grid",
"root": "card-grid",
"elements": {
"card-grid": {
"type": "grid",
"props": {
"columns": 3,
"gap": "md"
},
"slots": {
"items": ["card-1", "card-2", "card-3"]
}
},
"card-1": {
"type": "card",
"props": {
"featured": true
},
"slots": {
"header": ["card-1-header"],
"content": ["card-1-content"],
"footer": ["card-1-footer"]
}
},
"card-1-header": {
"type": "heading",
"props": {
"text": "Featured article"
}
},
"card-1-content": {
"type": "text",
"props": {
"content": "Learn how editorial teams use Canvas to review, refine, and publish AI-assisted content."
}
},
"card-1-footer": {
"type": "button-group",
"slots": {
"items": ["card-1-primary-action", "card-1-secondary-action"]
}
},
"card-1-primary-action": {
"type": "button",
"props": {
"label": "Read more",
"href": "/articles/canvas-workflows"
}
},
"card-1-secondary-action": {
"type": "button",
"props": {
"label": "Save for later",
"href": "/saved"
}
},
"card-2": {
"type": "card",
"props": {
"featured": false
},
"slots": {
"header": ["card-2-header"],
"content": ["card-2-content"],
"footer": ["card-2-footer"]
}
},
"card-2-header": {
"type": "heading",
"props": {
"text": "Documentation update"
}
},
"card-2-content": {
"type": "text",
"props": {
"content": "Review the latest guidance for authoring Workbench component mocks."
}
},
"card-2-footer": {
"type": "button",
"props": {
"label": "Open docs",
"href": "/docs/workbench-mocks"
}
},
"card-3": {
"type": "card",
"props": {
"featured": false
},
"slots": {
"header": ["card-3-header"],
"content": ["card-3-content"],
"footer": ["card-3-footer"]
}
},
"card-3-header": {
"type": "heading",
"props": {
"text": "Team workflow"
}
},
"card-3-content": {
"type": "text",
"props": {
"content": "Coordinate AI drafting, editorial review, and publishing approvals in one place."
}
},
"card-3-footer": {
"type": "button",
"props": {
"label": "See workflow",
"href": "/workflow"
}
}
}
}
]
```
--------------------------------
### Define Link Prop Schema
Source: https://project.pages.drupalcode.org/canvas/code-components/cli-tool/prop-schemas
Use this schema for URL or URI references. It accepts absolute URLs with `format: uri` or both absolute and relative URLs with `format: uri-reference`.
```yaml
type: string
format: uri-reference
examples:
- https://example.com
```
--------------------------------
### Fetch data with SWR
Source: https://project.pages.drupalcode.org/canvas/code-components/data-fetching
Use the SWR hook for general data fetching. Ensure a fetcher function is defined and imported. Data is displayed in the 'Data Fetch' pane.
```javascript
import useSWR from 'swr';
export default function Profile() {
const { data, error, isLoading } = useSWR(
'https://my-site.com/api/user',
fetcher,
);
if (error) return
failed to load
;
if (isLoading) return
loading...
;
return
hello {data.name}!
;
}
```
--------------------------------
### Mock entry with props only
Source: https://project.pages.drupalcode.org/canvas/code-components/workbench/mocks
Defines a mock entry using only the 'props' field for previewing component prop variations. The 'name' field labels the preview tab.
```json
[
{
"name": "Centered",
"props": {
"text": "Publish AI-assisted content with editorial control",
"eyebrow": "Build faster",
"textAlign": "center"
}
}
]
```
--------------------------------
### Define Link Prop (URI Format)
Source: https://project.pages.drupalcode.org/canvas/sdc-components/props
Use for absolute URLs only. The 'format: uri' ensures the value includes a scheme.
```yaml
link:
type: string
format: uri
title: 'Link URL'
examples: ['https://example.com/path']
```
--------------------------------
### Import React Package with esm.sh
Source: https://project.pages.drupalcode.org/canvas/code-components/packages
Import React packages from esm.sh. Append '?external=react,react-dom' to avoid multiple React versions.
```javascript
import { motion } from 'https://esm.sh/motion@12.23.26/react?external=react,react-dom';
```
--------------------------------
### Import Other Code Components
Source: https://project.pages.drupalcode.org/canvas/code-components
Import previously created components by prefixing their path with '@/components'. This allows for modularity and reuse of existing component logic.
```javascript
import Heading from '@/components/my_heading';
```
--------------------------------
### Basic Image Component Usage
Source: https://project.pages.drupalcode.org/canvas/sdc-components/image
Include the canvas:image component with essential properties like src and alt. This is the simplest way to render an image.
```twig
{% include 'canvas:image' with {
src: 'https://example.com/image.jpg',
alt: 'Example image',
width: 600,
height: 400,
} only %}
```
--------------------------------
### Define Link Prop (URI Reference Format)
Source: https://project.pages.drupalcode.org/canvas/sdc-components/props
Use for absolute or relative links. The 'format: uri-reference' allows full URIs or paths.
```yaml
link:
type: string
format: uri-reference
title: 'Link URL'
examples: ['/about', 'https://example.com']
```
--------------------------------
### Workbench Configuration
Source: https://project.pages.drupalcode.org/canvas/code-components/workbench
Create a canvas.config.json file in your project root to customize Workbench's scanning paths and alias base directory. This is useful when your project deviates from the default Canvas layout.
```json
{
"componentDir": "./components",
"pagesDir": "./pages",
"aliasBaseDir": "src",
"globalCssPath": "./src/components/global.css"
}
```
--------------------------------
### Define Image Object Prop Schema
Source: https://project.pages.drupalcode.org/canvas/code-components/cli-tool/prop-schemas
Use this schema to reference an image object. Only the file URL is required; other metadata like alt text, width, and height are optional.
```yaml
type: object
$ref: json-schema-definitions://canvas.module/image
examples:
- src: >-
https://images.unsplash.com/photo-1484959014842-cd1d967a39cf?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1770&q=80
alt: Woman playing the violin
width: 1770
height: 1180
```
--------------------------------
### Define Basic Text Input Prop Schema
Source: https://project.pages.drupalcode.org/canvas/code-components/cli-tool/prop-schemas
Use this schema for basic text input. It is stored as a string value.
```yaml
type: string
examples:
- Hello, world!
```
--------------------------------
### Define Video Object Prop Schema
Source: https://project.pages.drupalcode.org/canvas/code-components/cli-tool/prop-schemas
Use this schema to reference a video object. Only the file URL is required; other metadata like dimensions and poster are optional.
```yaml
type: object
$ref: json-schema-definitions://canvas.module/video
examples:
- src: https://media.istockphoto.com/id/1340051874/video/aerial-top-down-view-of-a-container-cargo-ship.mp4?s=mp4-640x640-is&k=20&c=5qPpYI7TOJiOYzKq9V2myBvUno6Fq2XM3ITPGFE8Cd8=
poster: https://example.com/600x400.png
```
--------------------------------
### Mock entry with props and slots
Source: https://project.pages.drupalcode.org/canvas/code-components/workbench/mocks
Defines a mock entry using 'props' and 'slots' to configure component props and map slots to element IDs. The 'elements' field defines the structure and content of child elements.
```json
[
{
"name": "Featured",
"props": {
"featured": true
},
"slots": {
"header": ["card-featured-header"],
"content": ["card-featured-content"],
"footer": ["card-featured-actions"]
},
"elements": {
"card-featured-header": {
"type": "heading",
"props": {
"text": "Featured article"
}
},
"card-featured-content": {
"type": "text",
"props": {
"content": "Learn how editorial teams use Canvas to review, refine, and publish AI-assisted content."
}
},
"card-featured-actions": {
"type": "button-group",
"props": {
"stacked": false
},
"slots": {
"items": ["card-featured-primary-action", "card-featured-secondary-action"]
}
},
"card-featured-primary-action": {
"type": "button",
"props": {
"label": "Get started",
"href": "/sign-up",
"variant": "primary"
}
},
"card-featured-secondary-action": {
"type": "button",
"props": {
"label": "Read more",
"href": "/articles/canvas-workflows"
}
}
}
}
]
```
--------------------------------
### Image Component with onLoad Callback
Source: https://project.pages.drupalcode.org/canvas/code-components/responsive-images
Provide an `onLoad` callback function to execute code once the image has fully loaded and the placeholder is removed. The callback receives the event object.
```javascript
console.log(e.target.naturalWidth, e.target.naturalHeight)}
/>
```
--------------------------------
### Import and Use Image Component
Source: https://project.pages.drupalcode.org/canvas/code-components/responsive-images
Import the Image component from drupal-canvas and use it with dynamic photo props. Ensure all required props (src, alt, width, height) are provided.
```javascript
import { Image } from 'drupal-canvas';
const MyComponent = ({ photo }) => {
return (
);
};
export default MyComponent;
```
--------------------------------
### Build Navigation from Drupal Linkset Endpoint
Source: https://project.pages.drupalcode.org/canvas/code-components/data-fetching
Builds a navigation menu using Drupal core's linkset endpoint. Requires `drupal-canvas` and `swr`. Uses `sortLinksetMenu` to process the data.
```javascript
import { sortLinksetMenu } from 'drupal-canvas';
import useSWR from 'swr';
const Navigation = () => {
const { data, isLoading, error } = useSWR(
'/system/menu/main/linkset',
async (url) => {
const response = await fetch(url);
return response.json();
}
);
if (error) return 'An error has occurred.';
if (isLoading) return 'Loading...';
const menu = sortLinksetMenu(data);
return (
{menu.map((item) => (
{item.title}
))}
);
};
export default Navigation;
```
--------------------------------
### Build Navigation from JSON:API Menu Items
Source: https://project.pages.drupalcode.org/canvas/code-components/data-fetching
Constructs a navigation menu from Drupal's JSON:API menu items. Requires `drupal-canvas` and `swr`. Uses `sortMenu` to order menu items.
```javascript
import { JsonApiClient, sortMenu } from 'drupal-canvas';
import useSWR from 'swr';
const client = new JsonApiClient();
const Navigation = () => {
const { data, isLoading, error } = useSWR(
['menu_items', 'main'],
([type, resourceId]) => client.getResource(type, resourceId)
);
if (error) return 'An error has occurred.';
if (isLoading) return 'Loading...';
const menu = sortMenu(data);
return (
{menu.map((item) => (
{item.title}
))}
);
};
export default Navigation;
```
--------------------------------
### Image Component with Static Values
Source: https://project.pages.drupalcode.org/canvas/code-components/responsive-images
Use the Image component with static values for src, alt, width, and height. This is not recommended as it prevents responsive image variants from being generated.
```javascript
```
--------------------------------
### Image Component with Eager Loading
Source: https://project.pages.drupalcode.org/canvas/code-components/responsive-images
Set the `loading` prop to 'eager' to force immediate loading of the image, overriding the default 'lazy' behavior.
```javascript
```
--------------------------------
### Image Component with Placeholder Prop
Source: https://project.pages.drupalcode.org/canvas/code-components/responsive-images
Set the `placeholder` prop to 'blur' to display a blurred image while the actual image loads, enhancing perceived performance.
```javascript
```
--------------------------------
### Define List of Integer Options Prop Schema
Source: https://project.pages.drupalcode.org/canvas/code-components/cli-tool/prop-schemas
Use this schema for a predefined list of integer options. The `meta:enum` property provides user-friendly labels for each enum value. Enum values cannot contain dots.
```yaml
type: integer
enum:
- 1
- 2
- 3
meta:enum:
1: Option 1
2: Option 2
3: Option 3
examples:
- 1
```
--------------------------------
### Define Formatted Text Input Prop Schema
Source: https://project.pages.drupalcode.org/canvas/code-components/cli-tool/prop-schemas
Use this schema for rich text content with HTML formatting support, displayed in a block context. Stored as a string.
```yaml
type: string
contentMediaType: text/html
x-formatting-context: block
examples:
-
This is formatted text with HTML.
```
--------------------------------
### Define List of Text Options Prop Schema
Source: https://project.pages.drupalcode.org/canvas/code-components/cli-tool/prop-schemas
Use this schema for a predefined list of text options. The `meta:enum` property provides user-friendly labels for each enum value. Enum values cannot contain dots.
```yaml
type: string
enum:
- option1
- option2
- option3
meta:enum:
option1: Option 1
option2: Option 2
option3: Option 3
examples:
- option1
```
--------------------------------
### Define String Prop for Component Title
Source: https://project.pages.drupalcode.org/canvas/sdc-components/props
Use for basic text input for short text content. The schema defines the 'title' prop as a string.
```yaml
title:
type: string
title: 'Component title'
examples: ['Hello World']
```
--------------------------------
### Define String Prop for Rich Text Content
Source: https://project.pages.drupalcode.org/canvas/sdc-components/props
Use for rich text content with HTML markup. The schema defines 'content' with 'text/html' media type.
```yaml
content:
type: string
title: 'Rich text content'
contentMediaType: text/html
x-formatting-context: block
examples: ['
This is formatted text
']
```
--------------------------------
### Define Default Viewport Sizes
Source: https://project.pages.drupalcode.org/canvas/apis/theme-settings
Configure default viewport sizes for the Canvas editor preview. These settings are applied when a theme's `{theme}.canvas.yml` file is present.
```yaml
viewports:
mobile: 468
tablet: 1024
desktop: 1920
large_desktop: 2560
```
--------------------------------
### Define Date Prop for Date Picker
Source: https://project.pages.drupalcode.org/canvas/sdc-components/props
Use for date selection using a date picker input. The schema specifies 'format: date'.
```yaml
event_date:
type: string
format: date
title: 'Event date'
examples: ['2024-12-25']
```
--------------------------------
### Define Image Object Prop
Source: https://project.pages.drupalcode.org/canvas/sdc-components/props
Use for image selection from the media library or uploads. The schema references a common image definition.
```yaml
image:
title: 'Component image'
$ref: json-schema-definitions://canvas.module/image
type: object
examples:
- src: '/path/to/image.jpg'
alt: 'Component image'
width: 800
height: 600
```
--------------------------------
### Define Integer Prop for Spacing
Source: https://project.pages.drupalcode.org/canvas/sdc-components/props
Use for numeric input, such as pixel values for spacing. Includes a minimum validation constraint.
```yaml
spacing:
type: integer
title: 'Spacing in pixels'
minimum: 0
examples: [20]
```
--------------------------------
### Responsive Sizing with Sizes Attribute
Source: https://project.pages.drupalcode.org/canvas/sdc-components/image
Utilize the 'sizes' attribute to inform the browser about different image sizes based on viewport width. This optimizes image loading for various devices.
```twig
{% include 'canvas:image' with image|merge({
sizes: '(max-width: 480px) 100vw, (max-width: 768px) 50vw, 33vw',
loading: 'lazy',
}) only %}
```
--------------------------------
### CSS for Enhanced List Layout and Counter
Source: https://project.pages.drupalcode.org/canvas/sdc-components/slots
Styles for horizontal list layout with horizontal scrolling and item basis, and for displaying counters before each list item with specific formatting.
```css
.list-direction-horizontal {
flex-direction: row;
overflow-x: auto;
&>* {
flex-shrink: 0;
flex-basis: 300px;
padding: 6px;
}
}
.list-with-counter >* {
counter-increment: list-number;
&:before {
font-size: 3rem;
color: darkgrey;
content: counter(list-number);
padding-inline: .5rem;
margin-inline-end: .5rem;
}
}
```
--------------------------------
### Conditionally Construct Class Names with clsx
Source: https://project.pages.drupalcode.org/canvas/code-components/packages
Use the `clsx` utility for efficiently building CSS class strings, especially with conditional logic.
```javascript
import { clsx } from 'clsx'
export default function Example() {
return (
// => 'foo bar baz'
);
};
```
--------------------------------
### Fetch Nodes with JSON:API
Source: https://project.pages.drupalcode.org/canvas/code-components/data-fetching
Fetches articles using the JSON:API client and displays them with links. Requires `drupal-canvas` and `swr`. Uses `getNodePath` for URL generation.
```javascript
import { getNodePath, JsonApiClient } from 'drupal-canvas';
import { DrupalJsonApiParams } from 'drupal-jsonapi-params';
import useSWR from 'swr';
const Articles = () => {
const client = new JsonApiClient();
const { data, error, isLoading } = useSWR(
[
'node--article',
{
queryString: new DrupalJsonApiParams()
.addSort('created', 'DESC')
.getQueryString(),
},
],
([type, options]) => client.getCollection(type, options)
);
if (error) return 'An error has occurred.';
if (isLoading) return 'Loading...';
return (
);
};
export default Articles;
```
--------------------------------
### Image Component with Style Prop
Source: https://project.pages.drupalcode.org/canvas/code-components/responsive-images
Apply custom CSS styles to the underlying image element using the `style` prop.
```javascript
```
--------------------------------
### Override JSON:API client defaults
Source: https://project.pages.drupalcode.org/canvas/code-components/data-fetching
Instantiate the JsonApiClient with custom baseUrl and options to override default configurations like serializer or cache.
```javascript
const client = new JsonApiClient('https://drupal-api-demo.party', {
serializer: undefined,
cache: undefined,
});
```
--------------------------------
### Basic List Component CSS Styling
Source: https://project.pages.drupalcode.org/canvas/sdc-components/slots
Provides CSS for a vertical list layout with a maximum height and an auto-scrollbar for the items. Includes hover effect for list items.
```css
.list-title {
font-size: 1.3rem;
font-weight: 700;
margin-block-end: 1rem;
}
.list-items {
display: flex;
gap: .5rem;
counter-reset: list-number;
flex-direction: column;
max-block-size: 300px;
overflow-y: auto;
& > *:hover {
background-color: lightgrey;;
}
}
```
--------------------------------
### Image Component with onError Callback
Source: https://project.pages.drupalcode.org/canvas/code-components/responsive-images
Implement an `onError` callback function to handle image loading failures. The callback is invoked if the image fails to load.
```javascript
console.error('Image failed to load')}
/>
```
--------------------------------
### Fetch collection with JSON:API
Source: https://project.pages.drupalcode.org/canvas/code-components/data-fetching
Fetch a collection of articles, including their tags, using the JSON:API client and DrupalJsonApiParams. Requires the JSON:API module to be enabled in Drupal.
```javascript
import { JsonApiClient } from 'drupal-canvas';
import { DrupalJsonApiParams } from 'drupal-jsonapi-params';
import useSWR from 'swr';
const client = new JsonApiClient();
export default function List() {
const { data, error, isLoading } = useSWR(
[
'node--article',
{
queryString: new DrupalJsonApiParams()
.addInclude(['field_tags'])
.getQueryString(),
},
],
([type, options]) => client.getCollection(type, options),
);
if (error) return 'An error has occurred.';
if (isLoading) return 'Loading...';
return (
{data.map((article) => (
{article.title}
))}
);
}
```
--------------------------------
### Image Component with Additional Properties
Source: https://project.pages.drupalcode.org/canvas/sdc-components/image
Extend the basic image component usage by merging additional properties like loading, sizes, class, and custom attributes. Useful for fine-tuning responsive behavior and adding custom elements.
```twig
{% include 'canvas:image' with image|merge({
loading: 'lazy',
sizes: '(max-width: 768px) 100vw, 50vw',
class: 'card--image',
attributes: create_attribute({
'data-testid': 'card-component-image',
}),
}) only %}
```
--------------------------------
### Define Required Props
Source: https://project.pages.drupalcode.org/canvas/sdc-components/validations
List props that are mandatory for a component under the 'required' key. Saving the page will be blocked until these props are filled.
```yaml
props:
type: object
required:
- text
text:
type: string
examples:
- "Hot"
```
--------------------------------
### Define List Component Metadata with Slots
Source: https://project.pages.drupalcode.org/canvas/sdc-components/slots
Defines a 'List' component with a 'title' prop and a 'content' slot for dynamic item insertion. The 'title' of the slot appears as placeholder text in Canvas.
```yaml
$schema: https://git.drupalcode.org/project/drupal/-/raw/HEAD/core/assets/schemas/v1/metadata.schema.json
name: List
status: stable
group: Music
description: List component, displays sdc children as a vertical numbered list.
props:
type: object
properties:
title:
type: string
title: List title
description: >
Title of the list
examples: ["My awesome list"]
slots:
content:
title: List items
description: >
Place any SDC in this slot, to add them to the list.
```
--------------------------------
### Image Component with Fill Prop
Source: https://project.pages.drupalcode.org/canvas/code-components/responsive-images
Utilize the `fill` prop to make the image fill its parent element, suitable for cases where dimensions are unknown. The parent must have a relative, fixed, or absolute position.
```javascript
```
--------------------------------
### Enable @tailwindcss/typography Plugin
Source: https://project.pages.drupalcode.org/canvas/code-components/packages
Add the @plugin directive to your Global CSS to enable the typography plugin.
```css
@plugin "@tailwindcss/typography";
```
--------------------------------
### Define Integer Prop Schema
Source: https://project.pages.drupalcode.org/canvas/code-components/cli-tool/prop-schemas
Use this schema for whole number values without decimal places.
```yaml
type: integer
examples:
- 42
```
--------------------------------
### Use Image Object Prop in Twig Template
Source: https://project.pages.drupalcode.org/canvas/sdc-components/props
Includes a Twig template for rendering an image, passing the 'image' prop object.
```twig
{% include 'canvas:image' with image only %}
```
--------------------------------
### Define Enum Prop for Dropdown
Source: https://project.pages.drupalcode.org/canvas/sdc-components/props
Renders as a dropdown with predefined options. 'meta:enum' can customize display labels for each option.
```yaml
alignment:
type: string
title: 'Text alignment'
enum: ['left', 'center', 'right']
meta:enum:
left: Left aligned
center: Center aligned
right: Right aligned
examples: ['center']
```
--------------------------------
### Define Boolean Prop Schema
Source: https://project.pages.drupalcode.org/canvas/code-components/cli-tool/prop-schemas
Use this schema for true or false values.
```yaml
type: boolean
examples:
- false
```
--------------------------------
### Define Number Prop Schema
Source: https://project.pages.drupalcode.org/canvas/code-components/cli-tool/prop-schemas
Use this schema for numeric values that can include decimal places.
```yaml
type: number
examples:
- 3.14
```
--------------------------------
### Singer SDC Component Metadata
Source: https://project.pages.drupalcode.org/canvas/sdc-components
Defines the metadata for the 'Singer' SDC component, including its name, group, description, and properties.
```yaml
$schema: 'https://git.drupalcode.org/project/drupal/-/raw/HEAD/core/assets/schemas/v1/metadata.schema.json'
name: Singer
status: stable
group: Music
description: Singer component, could be used to display one singer.
props:
type: object
required:
- name
properties:
name:
type: string
title: Name
description: Name of the singer.
examples: ['Michael Jackson','Bruno Mars']
genre:
type: string
title: Genre
description: Main music Genre of the singer
enum:
- Pop
- Jazz
- Soul
- Funk
- "Rock and Roll"
- Electro
examples: ['Pop']
image:
$ref: json-schema-definitions://canvas.module/image
type: object
title: Image
description: >
Image of the singer
examples:
- src: 'micro.webp'
alt: 'Nice picture of the singer'
width: 200
height: 300
```
--------------------------------
### Define Textarea Prop for Long Text
Source: https://project.pages.drupalcode.org/canvas/sdc-components/props
Use for longer text content that spans multiple lines. The schema uses a $ref to a textarea definition.
```yaml
description:
type: string
title: 'Description'
$ref: json-schema-definitions://canvas.module/textarea
examples: ['A longer description
that spans multiple lines']
```
--------------------------------
### Define a Jumbotron Component with Slots
Source: https://project.pages.drupalcode.org/canvas/code-components/slots
This component uses slots for 'header' and 'buttonFooter' to allow flexible content insertion. Slot names are camelCased when passed as parameters.
```javascript
const Jumbotron = ({ header, buttonFooter }) => {
return (
{header}
{buttonFooter}
);
};
export default Jumbotron;
```
--------------------------------
### Responsive Prose Size Modifiers
Source: https://project.pages.drupalcode.org/canvas/code-components/packages
Combine 'prose' with responsive prefixes and size modifiers like 'md:prose-lg' and 'lg:prose-xl' to control font size across different screen sizes.
```html
{body}
```
--------------------------------
### Use Integer Prop in Twig Template
Source: https://project.pages.drupalcode.org/canvas/sdc-components/props
Applies top padding to a div using the 'spacing' integer prop, specifying units in pixels.
```twig
Content with spacing
```
--------------------------------
### Use Date Prop in Twig Template
Source: https://project.pages.drupalcode.org/canvas/sdc-components/props
Renders a time element with the 'event_date' prop, formatting it to a human-readable date string.
```twig
```
--------------------------------
### Eager Loading for Above-the-Fold Images
Source: https://project.pages.drupalcode.org/canvas/sdc-components/image
Override the default lazy loading behavior to 'eager' for critical above-the-fold images. This ensures important images load immediately.
```twig
{% include 'canvas:image' with image|merge({
loading: 'eager', {# For hero images or critical content #}
}) only %}
```
--------------------------------
### Implement Integer Range Validation
Source: https://project.pages.drupalcode.org/canvas/sdc-components/validations
Add custom validations for props based on their types. For integer props, 'minimum' and 'maximum' can be used to define acceptable ranges.
```yaml
test_integer_range_minimum:
title: 'Integer, minimum=0'
type: integer
minimum: 0
```
--------------------------------
### Define Boolean Prop for Visibility
Source: https://project.pages.drupalcode.org/canvas/sdc-components/props
Use for true/false values, typically controlling the visibility of elements. The schema defines 'show_image' as a boolean.
```yaml
show_image:
type: boolean
title: 'Show image'
examples: [true]
```
--------------------------------
### Fetch related articles excluding current
Source: https://project.pages.drupalcode.org/canvas/code-components/data-fetching
Fetch a list of articles, excluding the current one, using getPageData and a JSON:API client. Includes a wrapper component to safely handle cases where mainEntity might be null or not an article.
```javascript
import { getPageData } from 'drupal-canvas';
import { JsonApiClient } from 'drupal-canvas';
import { DrupalJsonApiParams } from 'drupal-jsonapi-params';
import useSWR from 'swr'
const client = new JsonApiClient();
function RelatedArticles({ mainEntity }) {
const { bundle, entityTypeId, uuid } = mainEntity;
const { data, error, isLoading } = useSWR(
[
'node--article',
{
queryString: new DrupalJsonApiParams()
.addFilter('id', uuid, '<>') // Exclude current article by uuid.
.getQueryString(),
},
],
([type, options]) => client.getCollection(type, options),
);
return (...);
}
// Wrapper component to check for mainEntity existence and type before calling a hook since
// hooks cannot be called conditionally (React rules of hooks).
function RelatedArticlesWrapper() {
const { mainEntity } = getPageData();
// Return early if there is no mainEntity, or it is not an article node.
if (
!mainEntity ||
mainEntity.entityTypeId !== 'node' ||
mainEntity.bundle !== 'article'
) {
return null;
}
return ;
}
export default RelatedArticlesWrapper;
```
--------------------------------
### Enhanced List Component Props for Layout and Counter
Source: https://project.pages.drupalcode.org/canvas/sdc-components/slots
Adds 'direction' and 'with_counter' props to control list layout (vertical/horizontal) and display item counters. 'direction' accepts 'vertical' or 'horizontal'.
```yaml
direction:
type: string
title: List direction
enum: ['vertical','horizontal']
meta:enum:
vertical: Vertical
horizontal: horizontal
examples: ['vertical']
with_counter:
type: boolean
title: Add counter
description: Add a number to each list item
examples: [false]
```
--------------------------------
### Use Textarea Prop in Twig Template
Source: https://project.pages.drupalcode.org/canvas/sdc-components/props
Renders the 'description' prop within a div, using the 'nl2br' filter to convert newlines to HTML line breaks.
```twig
{{ description|nl2br }}
```
--------------------------------
### Use Custom Tailwind CSS Color Class
Source: https://project.pages.drupalcode.org/canvas/code-components/packages
Apply custom theme colors defined via `@theme` directive as utility classes in your component markup.
```javascript
export default function Example() {
return
Drupal Blue
;
}
```
--------------------------------
### Dark Mode with Prose Invert
Source: https://project.pages.drupalcode.org/canvas/code-components/packages
Utilize the 'prose-invert' class to apply an inverted color palette for dark mode backgrounds.
```html
{body}
```
--------------------------------
### List Component Twig Template
Source: https://project.pages.drupalcode.org/canvas/sdc-components/slots
Renders a list component with a title and a content area for dynamically inserted items. Uses BEM methodology for CSS class naming.
```twig
{# list.twig #}
{{ title }}
{{ content }}
```
--------------------------------
### Defining Image Props in SDC Metadata
Source: https://project.pages.drupalcode.org/canvas/sdc-components/image
Define image properties within your SDC component's metadata schema. This allows the component to accept and pass image configurations, ensuring consistency.
```yaml
$schema: https://git.drupalcode.org/project/drupal/-/raw/HEAD/core/assets/schemas/v1/metadata.schema.json
name: Card
props:
type: object
properties:
image:
$ref: json-schema-definitions://canvas.module/image
type: object
title: Card image
examples:
- src: https://placehold.co/400x300
alt: Card placeholder image
width: 400
height: 300
```
--------------------------------
### Define Custom Viewport Sizes
Source: https://project.pages.drupalcode.org/canvas/apis/theme-settings
Set custom viewport sizes for specific breakpoints, such as mobile and desktop. If a viewport ID is missing or invalid, Canvas falls back to its default width.
```yaml
viewports:
mobile: 375
desktop: 1440
```
--------------------------------
### Customize Tailwind CSS Theme Variables
Source: https://project.pages.drupalcode.org/canvas/code-components/packages
Define custom theme variables, such as colors, using the `@theme` directive to extend Tailwind CSS.
```css
@theme {
--color-drupal-blue: #009cde;
}
```
--------------------------------
### Singer SDC CSS Styling
Source: https://project.pages.drupalcode.org/canvas/sdc-components
CSS styles for the 'Singer' SDC component, defining its layout and the appearance of its elements.
```css
.singer {
display: flex;
align-items: center;
gap: 0.5rem;
}
.singer-image {
height: 50px; width: 50px;
object-fit: cover;
border-radius: 6px;
}
.singer-name { font-weight: bold; }
.singer-genre { font-weight: normal; }
```
--------------------------------
### Define Array Prop for Lists
Source: https://project.pages.drupalcode.org/canvas/sdc-components/props
Use for list inputs allowing multiple string values. Includes a maximum item count constraint.
```yaml
numbers:
type: array
title: 'List of numbers'
items:
type: string
maxItems: 10
examples: [['One', 'Two', 'Three']]
```
--------------------------------
### Enhanced List Component Twig Template with Dynamic Classes
Source: https://project.pages.drupalcode.org/canvas/sdc-components/slots
Dynamically applies CSS classes based on 'direction' and 'with_counter' props to control list appearance. Renders the list title and items.
```twig
{# list.twig #}
{% set classes = [
direction ? 'list-direction-' ~ direction,
with_counter ? 'list-with-counter'
]|join(' ') %}
{{ title }}
{{ content }}
```
--------------------------------
### Remove Prose Max-Width
Source: https://project.pages.drupalcode.org/canvas/code-components/packages
Add the 'max-w-none' class to the 'prose' component to allow content to fill its container without a built-in max-width.
```html
{body}
```
--------------------------------
### Use Link Prop in Twig Template
Source: https://project.pages.drupalcode.org/canvas/sdc-components/props
Renders an anchor tag with the 'link' prop as the href attribute.
```twig
Link text
```
--------------------------------
### Use String Prop in Twig Template
Source: https://project.pages.drupalcode.org/canvas/sdc-components/props
Renders the 'title' prop as an H2 element in the Twig template.
```twig