components.styles

bởi coinbase

Guidelines writing styles API (styles, classNames, and static classNames) for a CDS component. Use this skill when adding customization options to a React…

npx skills add https://github.com/coinbase/cds --skill components.styles

Goal: Add styles API (styles, classNames, and static classNames) to a CDS component and/or update the component documentation with styles documentation.

If no component name is provided, ask the user which component they want to add styles to.

Step 1: Locate the Component

Find the component source file:

packages/web/src/[source-category]/[ComponentName].tsx              # for web
packages/mobile/src/[source-category]/[ComponentName].tsx           # for mobile

Step 2: Evaluate Component Structure

⚠️ IMPORTANT: Adding styles/classNames props is a commitment to the component's internal structure.

Before adding styles API, carefully review the component's JSX structure:

  • Flag if the component could be simplified (e.g., unnecessary wrappers, redundant containers)
  • Do NOT add styles to elements that may be refactored - this creates breaking changes
  • Ask the user if you notice the component structure could be improved before committing to it

Once published, changing or removing selectors is a breaking change for consumers.

Step 3: Identify Styleable Elements

Review the component's JSX to identify elements that should be targetable via styles/classNames:

  • Root element: The outermost container element
  • Named sections: Elements with semantic meaning (e.g., start, content, end, header, footer)
  • Sub-components: Internal elements that users might want to customize
  • Conditional elements: Elements that render based on props

Approved Selector Names

IMPORTANT: Before adding a new selector name not in this list, get explicit confirmation from the user. When a new selector is approved, add it to this list.

Approved Selectors (alphabetical)

SelectorDescription
accessoryAccessory element (e.g., chevron, icon at end)
activeIndicatorActive indicator element (e.g., in tabs)
bottomContentBottom section content
carouselMain carousel track element
carouselContainerOuter carousel container
childrenContainerContainer wrapping children
contentMain content area
contentContainerContainer wrapping content
descriptionDescription text element
dayDate cell in a calendar grid
endEnd slot content (e.g., actions, icons)
fillFill/progress indicator within a track
headerHeader section
helperTextHelper/assistive text below content
iconIcon element
intermediaryMiddle/intermediary element between sections
labelLabel text element
labelsContainer for multiple labels
logoLogo element
mainContentPrimary content area
mediaMedia element (image, avatar, icon)
modalVisible modal card element
navigationNavigation controls (e.g., prev/next buttons)
overlayFull-viewport overlay/backdrop element
paginationPagination indicators
pressablePressable/interactive wrapper
progressProgress indicator element
progressBarProgressBar sub-component within a composed component
rootRoot/outermost container element
safeAreaSafe area region wrapping content
startStart slot content (e.g., back button)
stepIndividual step element (in steppers)
substepContainerContainer for nested sub-steps
subtitleSubtitle text element
tabTab element (in tabs)
tabsTabs container element
thumbDraggable thumb element (in sliders)
titleTitle text element
titleStackStack containing title/subtitle/description
titleStackContainerContainer wrapping titleStack
topContentTop section content
trackTrack/rail element (in progress bars, sliders)
triggerTrigger element that opens a dropdown/popover

JSDoc Convention for Selector Descriptions

Selector JSDoc comments describe what the element is, not what the prop does:

  • Sentence case, no trailing period
  • Concise noun phrase describing the element itself
  • Single-line format: /** Description */
  • For conditional elements, append context after a comma: /** Header element, only rendered on phone viewport */

Examples:

/** Root element */
/** Title text element */
/** Navigation controls element */
/** Header element, only rendered on phone viewport in horizontal direction */

Step 4: Add Styles API (Web Components)

For web components, add three things:

4.1 Static Class Names

Add a static classNames object with JSDoc comments. Place this before the component's type definitions:

/**
 * Static class names for [ComponentName] component parts.
 * Use these selectors to target specific elements with CSS.
 */
export const [componentName]ClassNames = {
  /** Root element */
  root: 'cds-[ComponentName]',
  /** [Concise element description] */
  [selectorName]: 'cds-[ComponentName]-[selectorName]',
  // ... more selectors as needed
} as const;

Naming conventions:

  • Use cds- prefix for all class names
  • Use PascalCase for component name: cds-NavigationBar
  • Use camelCase for sub-elements: cds-NavigationBar-contentWrapper, cds-Foo-titleStack
  • Keep names descriptive but concise

Example:

export const fooClassNames = {
  root: 'cds-Foo',
  contentWrapper: 'cds-Foo-contentWrapper',
  titleStack: 'cds-Foo-titleStack',
  helperText: 'cds-Foo-helperText',
} as const;

4.2 Update Component Props Type

Import and use the StylesAndClassNames utility type:

import type { StylesAndClassNames } from '../types';

export type [ComponentName]BaseProps = BoxBaseProps & {
  // ... other props (without styles/classNames)
};

export type [ComponentName]Props = [ComponentName]BaseProps & StylesAndClassNames<typeof [componentName]ClassNames> & Omit<BoxProps<[ComponentName]DefaultElement>, 'children'>;

This automatically generates the styles and classNames props based on your static classNames object.

4.3 Apply in Component Implementation

Apply the static classNames, dynamic classNames, and styles in the component:

import { cx } from '../cx';

// In the component:
<VStack
  className={cx([componentName]ClassNames.root, className, classNames?.root)}
  style={{ ...style, ...styles?.root }}
  // ... other props
>
  <HStack
    className={cx([componentName]ClassNames.contentWrapper, classNames?.contentWrapper)}
    style={styles?.contentWrapper}
  >
    {children}
  </HStack>
</VStack>

4.4 Add Tests for Static Class Names

Add tests to verify that static class names are applied correctly to the component. This ensures the class names remain stable for consumers who depend on them for CSS targeting.

Test pattern:

import { [componentName]ClassNames } from '../[ComponentName]';

describe('[ComponentName] static classNames', () => {
  it('applies static class names to component elements', () => {
    render(
      <[ComponentName]WithTheme
        start={<div>Start</div>}  // Include props that render conditional elements
      >
        <div>Children</div>
      </[ComponentName]WithTheme>,
    );

    // Test root element
    const root = screen.getByRole('[role]'); // or use testID/other selector
    expect(root).toHaveClass([componentName]ClassNames.root);

    // Test sub-elements using querySelector with the static class name
    expect(root.querySelector(`.${[componentName]ClassNames.start}`)).toBeInTheDocument();
    expect(root.querySelector(`.${[componentName]ClassNames.content}`)).toBeInTheDocument();
  });
});

Key testing principles:

  • Import the static classNames object from the component
  • Use toHaveClass() for elements accessible via roles/queries
  • Use querySelector() with the static class name for internal elements
  • Test all selectors, including those on conditionally rendered elements (pass appropriate props)

Example from NavigationBar:

import { navigationBarClassNames } from '../NavigationBar';

describe('NavigationBar static classNames', () => {
  it('applies static class names to component elements', () => {
    render(
      <NavigationBarWithTheme start={<div>Start</div>}>
        <div>Children</div>
      </NavigationBarWithTheme>,
    );

    const nav = screen.getByRole('navigation');
    expect(nav).toHaveClass(navigationBarClassNames.root);
    expect(nav.querySelector(`.${navigationBarClassNames.start}`)).toBeInTheDocument();
    expect(nav.querySelector(`.${navigationBarClassNames.content}`)).toBeInTheDocument();
  });
});

Step 5: Add Styles API (Mobile Components)

For mobile components, the pattern is simpler (no static classNames):

5.1 Add styles prop type

export type [ComponentName]Props = {
  // ... other props
  /** Custom styles for individual elements of the [ComponentName] component */
  styles?: {
    /** Root container element */
    root?: StyleProp<ViewStyle>;
    /** [Concise element description] */
    [selectorName]?: StyleProp<ViewStyle | TextStyle>;
    // ... more selectors as needed
  };
};

5.2 Apply in Component Implementation

<View style={[defaultStyles.root, styles?.root]}>
  <View style={[defaultStyles.content, styles?.content]}>{children}</View>
</View>

Step 6: Add JSDoc Notes for Special Cases

If any selectors have special rendering conditions, append the note after the element description with a comma:

styles?: {
  /** Header element, only rendered on phone viewport in horizontal direction */
  header?: React.CSSProperties;
};

Common cases to document:

  • Viewport-specific rendering (phone/tablet/desktop)
  • Direction-specific rendering (horizontal/vertical)
  • Conditional rendering based on props
  • Elements that only render with certain data (e.g., subSteps)

Reference: StylesAndClassNames Utility

The StylesAndClassNames utility type (from packages/web/src/types.ts) automatically generates:

// Given:
const fooClassNames = {
  root: 'cds-Foo',
  contentWrapper: 'cds-Foo-contentWrapper',
} as const;

// StylesAndClassNames<typeof fooClassNames> generates:
{
  styles?: {
    root?: React.CSSProperties;
    contentWrapper?: React.CSSProperties;
  };
  classNames?: {
    root?: string;
    contentWrapper?: string;
  };
}

Reference: NavigationBar Example

See packages/web/src/navigation/NavigationBar.tsx for a complete example of the styles API pattern:

  • Lines 16-28: Static classNames with JSDoc
  • Line 80: Using StylesAndClassNames type on regular Props (not BaseProps)
  • Lines 117, 140, 149: Applying classNames with cx()
  • Lines 125, 142, 152: Applying styles

See packages/web/src/navigation/__tests__/NavigationBar.test.tsx for static classNames test example:

  • NavigationBar static classNames describe block: Tests all static class names are applied

Step 7: Update Documentation

After adding the styles API to the component, update the documentation:

  1. Run the docgen to regenerate styles data:

    yarn nx run docs:docgen
    
  2. Create or update the styles documentation use the components.write-docs SKILL for general knowledge on how to write component documentation:

    • Create _webStyles.mdx with ComponentStylesTable and StylesExplorer
    • Create _mobileStyles.mdx with ComponentStylesTable (if mobile)
    • Update index.mdx to import and render the styles tables

Final Checklist

Before completing, verify:

  • Reviewed component structure for potential simplifications (flagged to user if found)
  • Selector names are from the approved list (or got user confirmation for new ones)
  • Each selector has a JSDoc comment following the convention (sentence case, no trailing period, concise noun phrase)
  • Class names follow cds-ComponentName-selectorName convention (camelCase)
  • Using StylesAndClassNames utility type on regular Props (not BaseProps) (web) or manual styles type (mobile)
  • Static classNames applied with cx() in component JSX (web only)
  • Dynamic classNames and styles props applied correctly
  • Special rendering conditions documented in JSDoc
  • Tests added for static classNames (web only) - see Step 4.4
  • Ran yarn nx run docs:docgen to regenerate styles data
  • Documentation updated to include new component styles information
  • Updated this file's "Approved Selector Names" table if new selectors were added

Thêm skills từ coinbase

git.repo-manager
coinbase
git.repo-manager — một kỹ năng có thể cài đặt cho các tác nhân AI, được xuất bản bởi coinbase/cds.
official
agentic-wallet
coinbase
Các thao tác ví tiền điện tử qua CLI awal — đăng nhập, kiểm tra số dư, gửi USDC/ETH/POL/SOL, giao dịch token, nạp tiền vào ví, và sử dụng giao thức thanh toán x402 để…
official
authenticate-wallet
coinbase
Xác thực ví dựa trên OTP qua email với kiểm tra trạng thái và xác thực. Quy trình đăng nhập hai bước: khởi tạo bằng email để nhận mã OTP 6 chữ số, sau đó xác minh với flowId và mã để hoàn tất xác thực. Bao gồm các quy tắc kiểm tra đầu vào cho email, flowId và OTP nhằm ngăn chặn tấn công shell trước khi thực thi lệnh. Cung cấp kiểm tra trạng thái, truy vấn số dư, lấy địa chỉ và truy cập cửa sổ ví thông qua các lệnh CLI đi kèm. Tất cả lệnh đều hỗ trợ đầu ra --json để máy có thể đọc được...
official
fund
coinbase
Nạp USDC vào ví qua Coinbase Onramp hoặc chuyển khoản trực tiếp. Mở giao diện đồng hành cho phép người dùng chọn số tiền định sẵn ($10, $20, $50) hoặc giá trị tùy chỉnh và chọn thanh toán qua Apple Pay, thẻ ghi nợ, chuyển khoản ngân hàng hoặc tài khoản Coinbase. Hỗ trợ nhiều phương thức thanh toán với thời gian xử lý khác nhau: thanh toán ngay lập tức qua thẻ và Apple Pay, 1–3 ngày đối với chuyển khoản ngân hàng ACH. Nạp tiền dưới dạng USDC trên mạng Base; ngoài ra, người dùng có thể gửi USDC trực tiếp đến địa chỉ ví qua npx awal@2.0.3...
official
monetize-service
coinbase
Triển khai một điểm cuối API trả phí mà các tác nhân khác có thể khám phá và thanh toán qua giao thức x402. Tính phí USDC mỗi yêu cầu trên Base bằng giao thức thanh toán HTTP 402; khách hàng thanh toán bằng giao dịch đã ký, không cần khóa API hoặc tài khoản. Tự động đăng ký điểm cuối với x402 Bazaar để các tác nhân khám phá khi bạn khai báo phần mở rộng khám phá. Hỗ trợ nhiều mức giá, tuyến đường ký tự đại diện và nhiều tùy chọn thanh toán cho mỗi điểm cuối bằng phần mềm trung gian Express. Được xây dựng trên @x402/express và @x402/core...
official
pay-for-service
coinbase
Gọi các API trả phí trên Base với thanh toán USDC tự động qua giao thức x402. Thực thi các yêu cầu HTTP (GET, POST, v.v.) đến các điểm cuối hỗ trợ x402 với thanh toán USDC nguyên tử được xử lý tự động. Hỗ trợ tùy chỉnh yêu cầu thông qua phương thức, nội dung JSON, tham số truy vấn và tiêu đề tùy chỉnh. Bao gồm các kiểm soát thanh toán: đặt số tiền USDC tối đa cho mỗi yêu cầu và nhóm các thao tác liên quan với ID tương quan. Yêu cầu xác thực ví và số dư USDC đủ; xác thực tất cả đầu vào của người dùng để ngăn chặn shell...
official
query-blockchain-data
coinbase
Truy vấn dữ liệu onchain blockchain trên Base bằng CDP SQL API qua x402. Sử dụng khi bạn hoặc người dùng muốn xem thông tin onchain về các block đã được giải mã,…
official
query-onchain-data
coinbase
Truy vấn dữ liệu onchain trên Base bằng SQL với thanh toán x402 theo từng truy vấn. Truy cập các sự kiện, giao dịch và khối đã được giải mã qua CoinbaseQL, một phương ngữ SQL dựa trên ClickHouse hỗ trợ joins, CTEs, truy vấn con và các hàm tiêu chuẩn. Ba bảng chính có sẵn: base.events (log hợp đồng thông minh đã giải mã), base.transactions (dữ liệu giao dịch đầy đủ) và base.blocks (siêu dữ liệu khối). Yêu cầu lọc trên các trường được đánh chỉ mục (event_signature, address, block_timestamp) trong truy vấn sự kiện để tránh quét toàn bộ bảng...
official