Install
$ agentstack add skill-drupal-canvas-skills-canvas-styling-conventions ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
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 inglobal.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 }) => (
{children}
);
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 }) => (
{children}
);
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
Click me
// Wrong
Click me
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 }) => (
{/* ... */}
);
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 }) => (
{children}
);
This approach ensures:
- Consistent colors across the design system
- Users select from curated, meaningful options (not arbitrary values)
- Easy theme updates by modifying
global.csstokens - Better accessibility through tested color combinations
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: drupal-canvas
- Source: drupal-canvas/skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.