canvas-styling-conventions

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Technology stack

技术栈

TechnologyPurpose
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.
技术用途
Tailwind CSS 4.1+样式设置
class-variance-authority (CVA)组件变体管理
clsx
+
tailwind-merge
via
cn()
类名合并
仅使用这些依赖项进行样式设置。请勿添加第三方CSS库或创建新的样式工具。

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.
  • 使用
    global.css
    中定义的Tailwind主题颜色(
    primary-*
    gray-*
    )。
  • 避免硬编码颜色值;请改用主题令牌。
  • 遵循示例中已有的焦点、悬停和激活状态模式。

The cn() utility

cn()工具

Use
cn()
to merge Tailwind classes. It combines
clsx
for conditional classes with
tailwind-merge
to resolve conflicting utilities. Import from either source:
jsx
import { cn } from '@/lib/utils';
// or
import { cn } from 'drupal-canvas';
Example usage:
jsx
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>
);
使用
cn()
合并Tailwind类。它结合了
clsx
用于条件类处理,以及
tailwind-merge
用于解决工具类冲突。可从以下任一来源导入:
jsx
import { cn } from '@/lib/utils';
// or
import { cn } from 'drupal-canvas';
示例用法:
jsx
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

接受className以进行样式自定义

Every component should accept a
className
prop to allow style overrides. Pass it to
cn()
as the last argument so consumer classes take precedence.
jsx
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.
每个组件都应接受
className
属性,以允许样式覆盖。将其作为最后一个参数传递给
cn()
,以便使用者的类具有更高优先级。
jsx
const Card = ({ colorScheme, className, children }) => (
  <div className={cn(cardVariants({ colorScheme }), className)}>{children}</div>
);
className
是实现/组合属性,而非编辑器属性。请勿将
className
添加到
component.yml
中,请勿将其标记为必填项,也请勿在Canvas元数据中显示它。

Tailwind 4 theme variables

Tailwind 4主题变量

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.
Canvas项目使用Tailwind CSS 4的
@theme
指令在
global.css
中定义设计令牌。
@theme { }
内部定义的变量会自动成为可用的Tailwind工具类。
请务必查看
global.css
中的可用设计令牌。
@theme
块是颜色、字体、断点和其他设计令牌的唯一可信来源。

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}
.
@theme
中定义CSS变量时,Tailwind 4会根据变量的命名空间前缀自动生成对应的工具类:
@theme
中的CSS变量
生成的工具类
--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:
响应式前缀
模式为:
--{namespace}-{name}
变为
{utility}-{name}

Examples

示例

Given this definition in
global.css
:
css
@theme {
  --color-primary-600: #1899cb;
  --color-primary-700: #1487b4;
}
You can use these colors with any color-accepting utility:
jsx
// 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.
假设
global.css
中有以下定义:
css
@theme {
  --color-primary-600: #1899cb;
  --color-primary-700: #1487b4;
}
你可以在任何接受颜色的工具类中使用这些颜色:
jsx
// 正确写法
<button className="bg-primary-600 hover:bg-primary-700 text-white">
  点击我
</button>

// 错误写法
<button className="bg-[#1899cb] text-white hover:bg-[#1487b4]">点击我</button>
对于罕见的一次性场景,添加主题令牌过于繁琐时,可使用任意值(例如
bg-[#xxx]
)。但如果某颜色在多个地方出现,或代表品牌/设计系统的值,请改为将其添加到
@theme
中。

Semantic aliases

语义别名

Theme variables can reference other variables to create semantic aliases:
css
@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).
主题变量可以引用其他变量来创建语义别名:
css
@theme {
  --color-primary-700: #1487b4;
  --color-primary-dark: var(--color-primary-700);
}
bg-primary-700
bg-primary-dark
都可以使用。当语义别名能更好地表达意图时(例如,用
primary-dark
表示更深的品牌变体),请使用语义别名。

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:
css
@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
).
当设计需要主题中尚未定义的颜色、字体或其他值时,请将其添加到
global.css
@theme
块中,而不是在组件中硬编码该值。
何时添加新主题令牌:
  • 设计引入了新的品牌颜色或色调
  • 需要为现有值创建语义别名(例如
    --color-accent
  • 设计重复使用特定的间距、字体或断点值
何时更新现有主题令牌:
  • 品牌颜色发生变化(更新十六进制值)
  • 需要在整个系统中调整设计令牌
示例 - 添加新颜色:
css
@theme {
  /* 现有令牌 */
  --color-primary-600: #1899cb;

  /* 用于成功状态的新令牌 */
  --color-success: #22c55e;
  --color-success-dark: #16a34a;
}
添加后,你可以立即使用
bg-success
text-success-dark
等工具类。
保持主题的有序性。 将相关令牌分组,并添加注释说明其用途。遵循
global.css
中已有的命名约定(例如,
primary-100
primary-900
的编号色调,
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:
yaml
undefined
切勿创建允许用户传递颜色代码(十六进制值、RGB、HSL或任何原始颜色字符串)的属性。 相反,请使用CVA定义一组少量的易读变体,这些变体映射到
global.css
中的设计令牌。
请务必查看
global.css
中的可用设计令牌。
其中定义的令牌(如
primary-*
gray-*
等)是颜色值的唯一可信来源。
错误示例 - 允许原始颜色值:
yaml
undefined

Wrong

错误写法

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

```jsx
// Wrong
const Card = ({ backgroundColor }) => (
  <div style={{ backgroundColor }}>{/* ... */}</div>
);
Correct - using CVA variants with design tokens:
yaml
undefined
props: properties: backgroundColor: title: Background Color type: string examples: - '#3b82f6'

```jsx
// 错误写法
const Card = ({ backgroundColor }) => (
  <div style={{ backgroundColor }}>{/* ... */}</div>
);
正确示例 - 使用CVA变体和设计令牌:
yaml
undefined

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

```jsx
// 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
props: properties: colorScheme: title: 配色方案 type: string enum: - default - primary - muted - dark meta:enum: default: 默认(白色) primary: 主色(蓝色) muted: 柔和色(浅灰) dark: 深色 examples: - default

```jsx
// 正确写法
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>
);
这种方法确保:
  • 设计系统中的颜色保持一致
  • 用户从经过筛选的、有意义的选项中选择(而非任意值)
  • 通过修改
    global.css
    令牌即可轻松更新主题
  • 通过经过测试的颜色组合提升可访问性