mcpField
W
webflow-code-component:convert-component

webflow-code-component:convert-component

github.com/webflow開発1331.0k 回インストール今日更新
リポジトリ

webflow-code-component:convert-component について

既存の React コンポーネントを分析し、Webflow Code Component の定義ファイルを作成するスキルです。props を Webflow の型に対応させ、互換性のための修正点も示します。

主な機能

  1. 01コンポーネント構造と props の分析
  2. 02TypeScript props の Webflow 型への対応
  3. 03非互換な React パターンの指摘
  4. 04.webflow.tsx 定義ファイルの生成
  5. 05設定と依存関係の確認

活用シーン

  1. 01React コンポーネントを Webflow 用に準備
  2. 02Designer で編集する props への変換
  3. 03SSR とスタイルの互換性確認
  4. 04未対応のコールバックやオブジェクトの修正計画

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/webflow/webflow-skills --skill webflow-code-component:convert-component

インストール後、Claude Code で/webflow-code-component:convert-componentを入力して読み込まれたか確認します。

同梱ファイルreferences/prop-types.md

詳細

コンポーネントの変換

既存の React コンポーネントの構造を分析し、適切な .webflow.tsx 定義ファイルを生成して、Webflow Code Component に変換します。

このスキルを使用する場合

使用する場合:

  • ユーザーが Webflow で使用したい既存の React コンポーネントを持っている場合
  • ユーザーが「変換」「適合」「Webflow で動作するようにしてほしい」と依頼した場合
  • ユーザーが React コンポーネントのファイルを提供し、Webflow 用の定義を求めている場合
  • 別の React プロジェクトからコンポーネントを移行する場合

使用しない場合:

  • コンポーネントをゼロから作成する場合(component-scaffold を使用してください)
  • ユーザーがコードコンポーネントについて知りたいだけの場合(直接回答してください)
  • コンポーネントがすでに Webflow コードコンポーネントである場合(component-audit を使用してください)

手順

フェーズ 1:既存コンポーネントを分析する
  1. React コンポーネントのファイルを読む:ソースコード全体を取得します

  2. コンポーネント情報を抽出する:

    • コンポーネント名(関数名/const 名)
    • Props のインターフェースまたは型定義
    • 各 prop の TypeScript 型
    • 定義されている場合はデフォルト値
    • コンポーネントが children を使用するかどうか
  3. 互換性のないパターンを特定する:

    パターン問題解決方法
    React Context の使用Context は Webflow コンポーネント間で機能しませんprops にリファクタリングするか、nano stores を使用します
    レンダリング中の window/documentSSR が失敗しますuseEffect でラップするか、ssr: false を設定します
    レンダリング中の localStorage/sessionStorageSSR が失敗しますuseEffect でラップするか、ssr: false を設定します
    複雑なオブジェクト propsWebflow の prop 型に対応付けられません個別の props に分割します
    関数 props(コールバック)Webflow ではサポートされていません削除するか、ロジックを内部化します
    useContext フックコンポーネント間では機能しません別の状態管理パターンを使用します
    外部 CSS のインポートShadow DOM では機能しない可能性があります代わりに .webflow.tsx でインポートします
    グローバルスタイルを参照する CSS クラスShadow DOM では機能しませんコンポーネントスコープのスタイルを使用します
    styled-componentsShadow DOM デコレーターが必要ですデコレーターを使って globals.ts を設定します
    Emotion (@emotion/styled)Shadow DOM デコレーターが必要ですデコレーターを使って globals.ts を設定します
  4. スタイル設定の方法を検出し、必要なセットアップを記録する:

    styled-components を使用している場合:

    npm i @webflow/styled-components-utils styled-components
    

    globals.ts を作成/更新します:

    import { styledComponentsShadowDomDecorator } from "@webflow/styled-components-utils";
    export const decorators = [styledComponentsShadowDomDecorator];
    

    Emotion を使用している場合:

    npm i @webflow/emotion-utils @emotion/cache @emotion/react
    

    globals.ts を作成/更新します:

    import { emotionShadowDomDecorator } from "@webflow/emotion-utils";
    export const decorators = [emotionShadowDomDecorator];
    

    どちらの CSS-in-JS 方式でも、webflow.json を更新します:

    styled-components:

    {
      "library": {
        "globals": "./src/globals.ts",
        "renderer": {
          "server": "@webflow/styled-components-utils/server"
        }
      }
    }
    

    Emotion:

    {
      "library": {
        "globals": "./src/globals.ts",
        "renderer": {
          "server": "@webflow/emotion-utils/server"
        }
      }
    }
    
  5. 問題を引き起こす可能性のある依存関係に印を付ける:

    • 大規模なライブラリ(バンドルサイズへの懸念)
    • ブラウザー専用のライブラリ
    • DOM を直接操作するライブラリ
フェーズ 2:Props を Webflow の型にマッピングする
  1. TypeScript → Webflow の prop 型マッピングを適用します:

    TypeScript の型Webflow の Propメモ
    stringprops.Text()短いテキストのデフォルト
    string(長文/HTML コンテンツ)props.RichText()prop 名が content/body/description を示す場合
    React.ReactNode / childrenprops.Slot()ネストされたコンテンツ用
    numberprops.Number()数値
    booleanprops.Boolean()切り替え
    "option1" | "option2"props.Variant()文字列リテラルのユニオン(options 配列が必要)
    enumprops.Variant()enum の値を options 配列に変換します(必須)
    { href: string; ... }props.Link(){ href, target?, preload? } オブジェクトを返します。コンポーネントが href/target props を個別に想定している場合は、ラッパーが必要になることがあります
    画像関連の型props.Image()画像の src、url など
    string(キャンバス上で編集可能なテキスト)props.TextNode()キャンバス上で直接編集できるテキスト用。multiline パラメーターがあります
    boolean(表示/非表示)props.Visibility()意味に沿った表示/非表示の切り替え
    string(HTML の id 用)props.Id()prop 名が「id」の場合、またはアクセシビリティに使用する場合
    複雑なオブジェクト分割複数のシンプルな props に分割します
    関数/コールバック削除サポートされていません
    配列要個別対応コンポーネントの再設計が必要になる場合があります
  2. 特別なケースを処理します:

    複雑なオブジェクトの props - 分割します:

    // Original
    interface Props {
      author: {
        name: string;
        avatar: string;
        bio: string;
      }
    }
    
    // Converted to flat props
    props: {
      authorName: props.Text({ name: "Author Name" }),
      authorAvatar: props.Image({ name: "Author Avatar" }),
      authorBio: props.RichText({ name: "Author Bio" })
    }
    

    シンプルな文字列以外を含むユニオン型:

    // Original - complex union
    type Size = "sm" | "md" | "lg" | { width: number; height: number };
    
    // Convert to Variant with only string options
    size: props.Variant({
      name: "Size",
      options: ["sm", "md", "lg", "custom"],
      defaultValue: "md"
    })
    // Note: Custom size would need additional Number props
    

    オプションの props - defaultValue をサポートする prop 型には defaultValue を指定します。注:Link、Image、Slot、Id は defaultValue を受け付けません。

    // Original
    interface Props {
      title?: string;
    }
    
    // Converted - provide default for types that support it
    title: props.Text({
      name: "Title",
      defaultValue: ""  // Empty string or sensible default
    })
    
フェーズ 3:プロジェクトのセットアップを確認する
  1. Webflow のセットアップが存在することを確認します:

    • プロジェクトルートに webflow.json があるか確認します
    • 必要な依存関係(@webflow/webflow-cli、@webflow/data-types、@webflow/react)があるか確認します
    • styled-components/Emotion を使用している場合は、デコレーターパッケージがあるか確認します
    • 不足している場合は、セットアップを提案するか、local-dev-setup スキルを案内します
  2. ファイルの配置場所を特定します:

    • 元のコンポーネントが置かれている場所を特定します
    • .webflow.tsx を作成する場所を決定します(同じディレクトリ)
    • インポートが必要な既存のスタイルがないか確認します
フェーズ 4:定義ファイルを生成する
  1. .webflow.tsx ファイルを作成します:
import { declareComponent } from "@webflow/react";
import { props } from "@webflow/data-types";
import { ComponentName } from "./ComponentName";
// Import styles if they exist
import "./ComponentName.module.css"; // or .css

export default declareComponent(ComponentName, {
  name: "ComponentName",
  description: "[Generated from component purpose]",
  group: "[Appropriate category]",
  props: {
    // Mapped props here
  },
  // decorators: [], // Optional — per-component decorators (e.g., for CSS-in-JS Shadow DOM support)
  options: {
    applyTagSelectors: true, // Default is false. Set to true to apply Webflow's tag selectors (e.g., h1, p styles) inside the component.
    ssr: true // or false if browser APIs detected
  }
});
  1. すべての props をマッピングした完全なファイルを提示します
フェーズ 5:必要な変更を記述する
  1. 元のコンポーネントに必要な変更点を列挙します:
## Required Changes to [ComponentName].tsx

### Must Fix (Component won't work without these):
- [ ] Issue 1: [Description and how to fix]
- [ ] Issue 2: [Description and how to fix]

### Recommended (Will improve Webflow integration):
- [ ] Recommendation 1
- [ ] Recommendation 2

### Props Mapping Summary:
| Original Prop | Webflow Prop | Notes |
|---------------|--------------|-------|
| title: string | props.Text() | Direct mapping |
| isOpen: boolean | props.Boolean() | Direct mapping |
| data: object | SPLIT → dataTitle, dataValue | Flattened |
| onClick: function | REMOVED | Not supported |
  1. 変更が必要な場合は、変更後のコンポーネントコードを提示します:
    • 更新後の TypeScript インターフェイスを示します
    • SSR に必要な useEffect ラッパーを示します
    • スタイルのインポート変更を示します
    • 該当する場合は CSS-in-JS のセットアップ要件を記載します

例

例 1:シンプルなコンポーネントの変換

ユーザープロンプト:

Convert this React component to work with Webflow:

// TestimonialCard.tsx
interface TestimonialCardProps {
  quote: string;
  authorName: string;
  authorTitle?: string;
  rating?: number;
}

export const TestimonialCard: React.FC<TestimonialCardProps> = ({
  quote,
  authorName,
  authorTitle = "",
  rating = 5
}) => {
  return (
    <div className="testimonial-card">
      <div className="stars">{"★".repeat(rating)}</div>
      <blockquote>{quote}</blockquote>
      <div className="author">
        <strong>{authorName}</strong>
        {authorTitle && <span>{authorTitle}</span>}
      </div>
    </div>
  );
};

回答:

## Component Analysis: TestimonialCard

### Props Detected:
| Prop | TypeScript Type | Webflow Mapping |
|------|-----------------|-----------------|
| quote | string | props.Text() |
| authorName | string | props.Text() |
| authorTitle | string (optional) | props.Text() |
| rating | number (optional) | props.Number() |

### Issues Found:
- **CSS class "testimonial-card"** - Uses global class that won't work in Shadow DOM
  - Fix: Convert to CSS Modules or import scoped styles

### No blocking issues - ready to convert!

---

## Generated Files

### TestimonialCard.webflow.tsx
```typescript
import { declareComponent } from "@webflow/react";
import { props } from "@webflow/data-types";
import { TestimonialCard } from "./TestimonialCard";
import "./TestimonialCard.module.css";

export default declareComponent(TestimonialCard, {
  name: "TestimonialCard",
  description: "Display customer testimonials with rating stars",
  group: "Display",
  props: {
    quote: props.Text({
      name: "Quote",
      defaultValue: "This product changed my life!"
    }),
    authorName: props.Text({
      name: "Author Name",
      defaultValue: "Jane Doe"
    }),
    authorTitle: props.Text({
      name: "Author Title",
      defaultValue: "CEO, Company"
    }),
    rating: props.Number({
      name: "Rating",
      defaultValue: 5,
      min: 1,
      max: 5
    })
  },
  options: {
    applyTagSelectors: true,
    ssr: true
  }
});
TestimonialCard.tsx に必要な変更
  1. CSS Modules に変換する - TestimonialCard.css の名前を TestimonialCard.module.css に変更し、インポートを更新します:
import styles from "./TestimonialCard.module.css";

// Default CSS Modules uses bracket notation:
<div className={styles["testimonial-card"]}>
<div className={styles["stars"]}>
// Dot notation (styles.testimonialCard) requires camelCase class names
// or a webpack override for css-loader.
セットアップの確認
  • webflow.json が存在することを確認します
  • 必要に応じて依存関係をインストールします:npm i --save-dev @webflow/webflow-cli @webflow/data-types @webflow/react

---

### Example 2: Component with Incompatible Patterns

**User prompt:**

これを Webflow のコードコンポーネントとして動作するようにします。

// Modal.tsx import { createContext, useContext, useState } from 'react';

const ModalContext = createContext<{ isOpen: boolean; toggle: () => void } | null>(null);

export const useModal = () => { const context = useContext(ModalContext); if (!context) throw new Error('useModal must be used within ModalProvider'); return context; };

interface ModalProps { trigger: React.ReactNode; children: React.ReactNode; onOpen?: () => void; onClose?: () => void; }

export const Modal: React.FC = ({ trigger, children, onOpen, onClose }) => { const [isOpen, setIsOpen] = useState(false);

const toggle = () => { const newState = !isOpen; setIsOpen(newState); if (newState && onOpen) onOpen(); if (!newState && onClose) onClose(); };

useEffect(() => { if (isOpen) { document.body.style.overflow = 'hidden'; } else { document.body.style.overflow = ''; } }, [isOpen]);

return ( <ModalContext.Provider value={{ isOpen, toggle }}>

{trigger}
{isOpen && (
<div className="modal-content" onClick={e => e.stopPropagation()}> {children}
)} </ModalContext.Provider> ); };


**Response:**

```markdown
## Component Analysis: Modal

### Issues Found:

| Issue | Severity | Resolution |
|-------|----------|------------|
| React Context (ModalContext) | Critical | Context won't work across Webflow components. Since this is internal to Modal, it's OK but exported useModal hook won't work. |
| document.body manipulation | Critical | SSR incompatible. Must set `ssr: false` or wrap in useEffect check. |
| onOpen/onClose callbacks | Warning | Function props not supported in Webflow. Must remove. |
| Global CSS classes | Warning | "modal-overlay", "modal-content" won't work in Shadow DOM. |

### Props Detected:
| Prop | TypeScript Type | Webflow Mapping | Status |
|------|-----------------|-----------------|--------|
| trigger | React.ReactNode | props.Slot() | OK |
| children | React.ReactNode | props.Slot() | OK |
| onOpen | function | REMOVE | Not supported |
| onClose | function | REMOVE | Not supported |

---

## Required Changes

### 1. Remove function props (onOpen, onClose)
These cannot be passed from Webflow Designer. Remove from interface and component.

### 2. Fix SSR issue with document.body
Either set `ssr: false` or add typeof check:

```typescript
useEffect(() => {
  if (typeof document === 'undefined') return;
  // ... rest of effect
}, [isOpen]);
3. CSS Modules に変換する

スタイルの名前を変更し、クラス参照を更新します。

4. エクスポートされた useModal フックを削除する

これは外部コンポーネントでは動作しません。ModalContext は内部専用にしてください。


生成されたファイル

Modal.webflow.tsx
import { declareComponent } from "@webflow/react";
import { props } from "@webflow/data-types";
import { Modal } from "./Modal";
import "./Modal.module.css";

export default declareComponent(Modal, {
  name: "Modal",
  description: "Overlay modal dialog with trigger element",
  group: "Interactive",
  props: {
    trigger: props.Slot({
      name: "Trigger"
    }),
    children: props.Slot({
      name: "Content"
    })
  },
  options: {
    applyTagSelectors: true,
    ssr: false  // Required due to document.body usage
  }
});
更新された Modal.tsx
import { useState, useEffect } from 'react';
import styles from "./Modal.module.css";

interface ModalProps {
  trigger: React.ReactNode;
  children: React.ReactNode;
  // Removed: onOpen, onClose - not supported in Webflow
}

export const Modal: React.FC<ModalProps> = ({ trigger, children }) => {
  const [isOpen, setIsOpen] = useState(false);

  const toggle = () => setIsOpen(!isOpen);

  useEffect(() => {
    if (typeof document === 'undefined') return;

    if (isOpen) {
      document.body.style.overflow = 'hidden';
    } else {
      document.body.style.overflow = '';
    }

    return () => {
      document.body.style.overflow = '';
    };
  }, [isOpen]);

  return (
    <>
      <div onClick={toggle}>{trigger}</div>
      {isOpen && (
        <div className={styles["overlay"]} onClick={toggle}>
          <div className={styles["content"]} onClick={e => e.stopPropagation()}>
            {children}
          </div>
        </div>
      )}
    </>
  );
};
必要なセットアップ
npm i --save-dev @webflow/webflow-cli @webflow/data-types @webflow/react

---

### Example 3: Component with Complex Object Props

**User prompt:**

Webflow 用に変換します。

interface Product { id: string; name: string; price: number; image: string; category: 'electronics' | 'clothing' | 'home'; }

interface ProductCardProps { product: Product; showBadge?: boolean; }

export const ProductCard = ({ product, showBadge = true }: ProductCardProps) => (

{product.name} {showBadge && {product.category}}
{product.name}

${product.price}

); ```

Response:

## Component Analysis: ProductCard

### Complex Props Detected:

The `product` prop is a complex object that must be flattened for Webflow:

| Original | Flattened Props |
|----------|-----------------|
| product.id | (Not needed in UI - remove) |
| product.name | productName: props.Text() |
| product.price | productPrice: props.Number() |
| product.image | productImage: props.Image() |
| product.category | productCategory: props.Variant() |
| showBadge | showBadge: props.Boolean() |

---

## Generated Files

### ProductCard.webflow.tsx
```typescript
import { declareComponent } from "@webflow/react";
import { props } from "@webflow/data-types";
import { ProductCard } from "./ProductCard";
import "./ProductCard.module.css";

export default declareComponent(ProductCard, {
  name: "ProductCard",
  description: "Product display card with image, name, price, and category",
  group: "Display",
  props: {
    productName: props.Text({
      name: "Product Name",
      defaultValue: "Product Title"
    }),
    productPrice: props.Number({
      name: "Price",
      defaultValue: 29.99
    }),
    productImage: props.Image({
      name: "Product Image"
    }),
    productCategory: props.Variant({
      name: "Category",
      options: ["electronics", "clothing", "home"],
      defaultValue: "electronics"
    }),
    showBadge: props.Boolean({
      name: "Show Category Badge",
      defaultValue: true
    })
  },
  options: {
    applyTagSelectors: true,
    ssr: true
  }
});
更新された ProductCard.tsx
import styles from "./ProductCard.module.css";

interface ProductCardProps {
  productName: string;
  productPrice: number;
  productImage?: { src: string; alt?: string };
  productCategory: 'electronics' | 'clothing' | 'home';
  showBadge?: boolean;
}

export const ProductCard = ({
  productName,
  productPrice,
  productImage,
  productCategory,
  showBadge = true
}: ProductCardProps) => (
  <div className={styles["card"]}>
    {productImage && (
      <img src={productImage.src} alt={productImage.alt || productName} />
    )}
    {showBadge && <span className={styles["badge"]}>{productCategory}</span>}
    <h3>{productName}</h3>
    <p>${productPrice.toFixed(2)}</p>
  </div>
);
移行に関する注意:
  • product オブジェクトは個別の props に分割されています
  • 各 prop は Webflow Designer で直接編集できるようになりました
  • product.id は UI に表示されないため削除されました
  • Image prop は Webflow の Image 型を使用するようになりました({ src, alt } を提供します)

---

### Example 4: Component with styled-components

**User prompt:**

この styled-components の React コンポーネントを Webflow 用に変換します。

// Button.tsx import styled from 'styled-components';

const StyledButton = styled.button<{ variant: 'primary' | 'secondary' }>` padding: 12px 24px; border-radius: 8px; font-weight: 600; background: ${props => props.variant === 'primary' ? '#3b82f6' : '#e5e7eb'}; color: ${props => props.variant === 'primary' ? 'white' : '#1f2937'};

&:hover { opacity: 0.9; } `;

interface ButtonProps { label: string; variant?: 'primary' | 'secondary'; disabled?: boolean; }

export const Button = ({ label, variant = 'primary', disabled = false }: ButtonProps) => ( {label} );


**Response:**

```markdown
## Component Analysis: Button

### Styling Approach Detected: styled-components

styled-components requires a Shadow DOM decorator to work in Webflow.

### Props Detected:
| Prop | TypeScript Type | Webflow Mapping |
|------|-----------------|-----------------|
| label | string | props.Text() |
| variant | 'primary' \| 'secondary' | props.Variant() |
| disabled | boolean | props.Boolean() |

### No blocking issues - ready to convert!

---

## Required Setup for styled-components

**1. Install dependencies:**
```bash
npm i @webflow/styled-components-utils styled-components
npm i -D @types/styled-components

2. src/globals.ts を作成/更新します:

import { styledComponentsShadowDomDecorator } from "@webflow/styled-components-utils";
export const decorators = [styledComponentsShadowDomDecorator];

3. webflow.json を更新します:

{
  "library": {
    "name": "My Library",
    "components": ["./src/**/*.webflow.@(js|jsx|mjs|ts|tsx)"],
    "globals": "./src/globals.ts"
  }
}

生成されたファイル

Button.webflow.tsx
import { declareComponent } from "@webflow/react";
import { props } from "@webflow/data-types";
import { Button } from "./Button";
// No CSS import needed - styled-components handles styles

export default declareComponent(Button, {
  name: "Button",
  description: "Styled button with primary and secondary variants",
  group: "Interactive",
  props: {
    label: props.Text({
      name: "Label",
      defaultValue: "Click me"
    }),
    variant: props.Variant({
      name: "Variant",
      options: ["primary", "secondary"],
      defaultValue: "primary"
    }),
    disabled: props.Boolean({
      name: "Disabled",
      defaultValue: false,
      trueLabel: "Disabled",
      falseLabel: "Enabled"
    })
  },
  options: {
    applyTagSelectors: true,
    ssr: true
  }
});
Button.tsx の変更は不要です

コンポーネントはそのまま使用できます。globals.ts の styled-components デコレーターが Shadow DOM へのスタイル注入を自動的に処理します。

セットアップのチェックリスト
  • @webflow/styled-components-utils をインストールします
  • デコレーターを含む globals.ts を作成します
  • globals を参照するよう webflow.json を更新します
  • npx webflow library share でデプロイします

## Guidelines

### When to Recommend Component Redesign

Some components fundamentally don't fit the Webflow model:

1. **Heavy Context usage**: If component relies on app-wide context, suggest redesign
2. **Complex state machines**: May need simplification
3. **Tightly coupled components**: Each needs to be independent in Webflow
4. **Components that render portals**: Consider if portal is necessary

### Default Value Strategy

Always provide sensible defaults:
- Text props: Representative example text
- Numbers: Common/typical value
- Booleans: Most common use case
- Variants: Most popular option
- Images: Can be undefined (optional)
- Slots: No default needed

### Props Naming for Webflow

Make prop names designer-friendly:
- Use descriptive names: `buttonText` not `txt`
- Avoid abbreviations: `imageSource` not `imgSrc`
- Group related props with prefixes: `authorName`, `authorAvatar`, `authorBio`

### SSR Decision

Set `ssr: false` if component:
- Accesses `window`, `document`, `navigator`
- Uses `localStorage` or `sessionStorage`
- Manipulates DOM directly
- Uses libraries that require browser APIs
- Renders canvas, WebGL, or maps

コメント