canvas-styling-conventions

Tailwind CSS 4.1+ Styling

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "canvas-styling-conventions" with this command: npx skills add acquia/nebula/acquia-nebula-canvas-styling-conventions

Technology stack

Technology Purpose

Tailwind CSS 4.1+ Styling

class-variance-authority (CVA) Component variants

clsx

  • tailwind-merge via cn()

Class name merging

Only use these dependencies for styling. Do not add third-party CSS libraries or create new styling utilities.

Styling conventions

  • Use Tailwind's theme colors (primary-* , gray-* ) defined in global.css .

  • Avoid hardcoded color values; use theme tokens instead.

  • Follow the existing focus, hover, and active state patterns from examples.

The cn() utility

Use cn() to merge Tailwind classes. It combines clsx for conditional classes with tailwind-merge to resolve conflicting utilities. Import from either source:

import { cn } from "@/lib/utils"; // or import { cn } from "drupal-canvas";

Example usage:

const Button = ({ variant, className, children }) => ( <button className={cn( "rounded px-4 py-2", variant === "primary" && "bg-primary-600 text-white", variant === "secondary" && "bg-gray-200 text-gray-800", className, )}

{children}

</button> );

Accept className for style customization

Every component should accept a className prop to allow style overrides. Pass it to cn() as the last argument so consumer classes take precedence.

const Card = ({ colorScheme, className, children }) => ( <div className={cn(cardVariants({ colorScheme }), className)}>{children}</div> );

className is an implementation/composition prop, not an editor prop. Do not add className to component.yml , do not mark it as required, and do not surface it in Canvas metadata.

Tailwind 4 theme variables

Canvas projects use Tailwind CSS 4's @theme directive to define design tokens in global.css . Variables defined inside @theme { } automatically become available as Tailwind utility classes.

Always check global.css for available design tokens. The @theme block is the source of truth for colors, fonts, breakpoints, and other design tokens.

How theme variables map to utility classes

When you define a CSS variable in @theme , Tailwind 4 automatically generates corresponding utility classes based on the variable's namespace prefix:

CSS Variable in @theme

Generated Utility Classes

--color-primary-600: #xxx

bg-primary-600 , text-primary-600 , border-primary-600

--color-gray-100: #xxx

bg-gray-100 , text-gray-100 , border-gray-100

--font-sans: ...

font-sans

--breakpoint-md: 48rem

md: responsive prefix

The pattern is: --{namespace}-{name} becomes {utility}-{name} .

Examples

Given this definition in global.css :

@theme { --color-primary-600: #1899cb; --color-primary-700: #1487b4; }

You can use these colors with any color-accepting utility:

// Correct <button className="bg-primary-600 hover:bg-primary-700 text-white"> Click me </button>

// Wrong <button className="bg-[#1899cb] text-white hover:bg-[#1487b4]">Click me</button>

Arbitrary values (e.g., bg-[#xxx] ) are acceptable for rare, one-off cases where adding a theme variable would be overkill. However, if a color appears in multiple places or represents a brand/design system value, add it to @theme

instead.

Semantic aliases

Theme variables can reference other variables to create semantic aliases:

@theme { --color-primary-700: #1487b4; --color-primary-dark: var(--color-primary-700); }

Both bg-primary-700 and bg-primary-dark will work. Use semantic aliases when they better express intent (e.g., primary-dark for a darker brand variant).

Adding or updating theme variables

When a design requires a color, font, or other value not yet defined in the theme, add it to the @theme block in global.css rather than hardcoding the value in a component.

When to add new theme variables:

  • A design introduces a new brand color or shade

  • You need a semantic alias for an existing value (e.g., --color-accent )

  • The design uses a specific spacing, font, or breakpoint value repeatedly

When to update existing theme variables:

  • The brand colors change (update the hex values)

  • Design tokens need adjustment across the system

Example - adding a new color:

@theme { /* Existing tokens */ --color-primary-600: #1899cb;

/* New token for a success state */ --color-success: #22c55e; --color-success-dark: #16a34a; }

After adding, you can immediately use bg-success , text-success-dark , etc.

Keep the theme organized. Group related tokens together with comments explaining their purpose. Follow the existing naming conventions in global.css

(e.g., numbered shades like primary-100 through primary-900 , semantic names like primary-dark ).

Color props must use variants, not color codes

Never create props that allow users to pass color codes (hex values, RGB, HSL, or any raw color strings). Instead, define a small set of human-readable variants using CVA that map to the design tokens in global.css .

Always check global.css for available design tokens. The tokens defined there (such as primary-* , gray-* , etc.) are the source of truth for color values.

Wrong - allowing raw color values:

Wrong

props: properties: backgroundColor: title: Background Color type: string examples: - "#3b82f6"

// Wrong const Card = ({ backgroundColor }) => ( <div style={{ backgroundColor }}>{/* ... */}</div> );

Correct - using CVA variants with design tokens:

Correct

props: properties: colorScheme: title: Color Scheme type: string enum: - default - primary - muted - dark meta:enum: default: Default (White) primary: Primary (Blue) muted: Muted (Light Gray) dark: Dark examples: - default

// Correct import { cva } from "class-variance-authority";

const cardVariants = cva("rounded-lg p-6", { variants: { colorScheme: { default: "bg-white text-black", primary: "bg-primary-600 text-white", muted: "bg-gray-100 text-gray-700", dark: "bg-gray-900 text-white", }, }, defaultVariants: { colorScheme: "default", }, });

const Card = ({ colorScheme, children }) => ( <div className={cardVariants({ colorScheme })}>{children}</div> );

This approach ensures:

  • Consistent colors across the design system

  • Users select from curated, meaningful options (not arbitrary values)

  • Easy theme updates by modifying global.css tokens

  • Better accessibility through tested color combinations

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

canvas-component-metadata

No summary provided by upstream source.

Repository SourceNeeds Review
General

canvas-component-utils

No summary provided by upstream source.

Repository SourceNeeds Review
General

canvas-component-upload

No summary provided by upstream source.

Repository SourceNeeds Review
General

nebula-component-validation

No summary provided by upstream source.

Repository SourceNeeds Review