Convertir un composant
Convertir un composant React existant en composant Webflow en analysant sa structure et en générant le fichier de définition .webflow.tsx approprié.
Quand utiliser cette compétence
À utiliser quand :
- L'utilisateur a un composant React existant qu'il veut utiliser dans Webflow
- L'utilisateur demande de « convertir », « adapter » ou « faire fonctionner avec Webflow »
- L'utilisateur fournit un fichier de composant React et veut une définition Webflow
- L'utilisateur migre des composants depuis un autre projet React
À NE PAS utiliser quand :
- Créer un composant à partir de zéro (utiliser component-scaffold)
- L'utilisateur veut juste comprendre les composants de code (répondre directement)
- Le composant est déjà un composant Webflow (utiliser component-audit)
Instructions
Phase 1 : Analyser le composant existant
-
Lire le fichier du composant React : Obtenir le code source complet
-
Extraire les informations du composant :
- Nom du composant (nom de fonction/const)
- Interface ou définition de type des props
- Type TypeScript de chaque prop
- Valeurs par défaut si définies
- Si le composant utilise
children
-
Identifier les motifs incompatibles :
Motif Problème Résolution Utilisation de React Context Context ne fonctionne pas entre les composants Webflow Refactoriser en props ou utiliser nano stores window/documentdans le renduSSR échouera Envelopper dans useEffect ou définir ssr: falselocalStorage/sessionStoragedans le renduSSR échouera Envelopper dans useEffect ou définir ssr: falseProps d'objet complexe Impossible de mapper aux types de prop Webflow Diviser en props individuelles Props de fonction (callbacks) Non supporté dans Webflow Supprimer ou internaliser la logique Hook useContextNe fonctionne pas entre les composants Utiliser des motifs d'état alternatifs Imports CSS externes Peut ne pas fonctionner en Shadow DOM Importer dans .webflow.tsx à la place Références de classe CSS aux styles globaux Ne fonctionnera pas en Shadow DOM Utiliser des styles limités au composant styled-components Nécessite un décorateur Shadow DOM Configurer globals.ts avec décorateur Emotion (@emotion/styled) Nécessite un décorateur Shadow DOM Configurer globals.ts avec décorateur -
Détecter l'approche de style et noter la configuration requise :
Si utilisation de styled-components :
npm i @webflow/styled-components-utils styled-componentsCréer/mettre à jour
globals.ts:import { styledComponentsShadowDomDecorator } from "@webflow/styled-components-utils"; export const decorators = [styledComponentsShadowDomDecorator];Si utilisation d'Emotion :
npm i @webflow/emotion-utils @emotion/cache @emotion/reactCréer/mettre à jour
globals.ts:import { emotionShadowDomDecorator } from "@webflow/emotion-utils"; export const decorators = [emotionShadowDomDecorator];Pour les deux approches CSS-in-JS, mettre à jour
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" } } } -
Signaler les dépendances susceptibles de causer des problèmes :
- Grandes bibliothèques (préoccupation de taille du bundle)
- Bibliothèques uniquement pour le navigateur
- Bibliothèques qui manipulent le DOM directement
Phase 2 : Mapper les props aux types Webflow
-
Appliquer le mappage TypeScript → type de prop Webflow :
Type TypeScript Prop Webflow Notes stringprops.Text()Défaut pour texte court string(contenu long/HTML)props.RichText()Si le nom de la prop suggère contenu/body/description React.ReactNode/childrenprops.Slot()Pour contenu imbriqué numberprops.Number()Valeurs numériques booleanprops.Boolean()Bascules "option1" \| "option2"props.Variant()Unions littérales de chaînes (nécessite tableau options)enumprops.Variant()Convertir valeurs enum en tableau options(requis){ href: string; ... }props.Link()Retourne objet { href, target?, preload? }— peut nécessiter enveloppe si le composant s'attend à des propshref/targetdistinctsTypes liés aux images props.Image()Src d'image, url, etc. string(texte éditable sur canvas)props.TextNode()Pour texte éditable directement sur le canvas ; a paramètre multilineboolean(afficher/masquer)props.Visibility()Basculement sémantique afficher/masquer string(pour id HTML)props.Id()Si prop nommée « id » ou utilisée pour l'accessibilité Objets complexes DIVISER Diviser en plusieurs props simples Fonctions/callbacks SUPPRIMER Non supporté Tableaux SPÉCIAL Peut nécessiter refonte du composant -
Gérer les cas particuliers :
Props d'objet complexe - Les diviser :
// Original interface Props { author: { name: string; avatar: string; bio: string; } } // Converti en props plates props: { authorName: props.Text({ name: "Author Name" }), authorAvatar: props.Image({ name: "Author Avatar" }), authorBio: props.RichText({ name: "Author Bio" }) }Types union avec plus que de simples chaînes :
// Original - union complexe type Size = "sm" | "md" | "lg" | { width: number; height: number }; // Convertir en Variant avec uniquement options chaîne size: props.Variant({ name: "Size", options: ["sm", "md", "lg", "custom"], defaultValue: "md" }) // Remarque : custom size nécessiterait des props Number supplémentairesProps optionnelles - Fournir defaultValue pour les types de prop qui le supportent. Remarque : Link, Image, Slot et Id n'acceptent pas defaultValue.
// Original interface Props { title?: string; } // Converti - fournir défaut pour types qui le supportent title: props.Text({ name: "Title", defaultValue: "" // Chaîne vide ou défaut sensé })
Phase 3 : Vérifier la configuration du projet
-
Vérifier que la configuration Webflow existe :
- Chercher
webflow.jsonà la racine du projet - Chercher dépendances requises (@webflow/webflow-cli, @webflow/data-types, @webflow/react)
- Si utilisation de styled-components/Emotion, chercher packages décorateur
- Si manquant, proposer de configurer ou diriger vers compétence local-dev-setup
- Chercher
-
Déterminer les emplacements des fichiers :
- Identifier où vit le composant original
- Déterminer où
.webflow.tsxdoit être créé (même répertoire) - Chercher styles existants à importer
Phase 4 : Générer le fichier de définition
- Créer le fichier
.webflow.tsx:
import { declareComponent } from "@webflow/react";
import { props } from "@webflow/data-types";
import { ComponentName } from "./ComponentName";
// Importer styles s'ils existent
import "./ComponentName.module.css"; // ou .css
export default declareComponent(ComponentName, {
name: "ComponentName",
description: "[Généré à partir de la finalité du composant]",
group: "[Catégorie appropriée]",
props: {
// Props mappées ici
},
// decorators: [], // Optionnel — décorateurs par composant (ex. pour support Shadow DOM CSS-in-JS)
options: {
applyTagSelectors: true, // Défaut est false. Définir à true pour appliquer les sélecteurs de balise Webflow (ex. styles h1, p) dans le composant.
ssr: true // ou false si APIs du navigateur détectées
}
});
- Fournir le fichier complet avec tous les props mappés
Phase 5 : Documenter les modifications requises
- Lister les modifications nécessaires au composant original :
## Modifications requises pour [ComponentName].tsx
### Doit corriger (Le composant ne fonctionnera pas sans) :
- [ ] Problème 1 : [Description et comment corriger]
- [ ] Problème 2 : [Description et comment corriger]
### Recommandé (Améliorera l'intégration Webflow) :
- [ ] Recommandation 1
- [ ] Recommandation 2
### Résumé du mappage des props :
| Prop original | Prop Webflow | Notes |
|---------------|--------------|-------|
| title: string | props.Text() | Mappage direct |
| isOpen: boolean | props.Boolean() | Mappage direct |
| data: object | DIVISER → dataTitle, dataValue | Aplati |
| onClick: function | SUPPRIMÉ | Non supporté |
- Fournir code de composant modifié si modifications nécessaires :
- Afficher l'interface TypeScript mise à jour
- Afficher tout enveloppe useEffect nécessaire pour SSR
- Afficher modifications d'import de style
- Noter exigences de configuration CSS-in-JS si applicable
Exemples
Exemple 1 : Conversion de composant simple
Demande utilisateur :
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>
);
};
Réponse :
## Analyse du composant : TestimonialCard
### Props détectés :
| Prop | Type TypeScript | Mappage Webflow |
|------|-----------------|-----------------|
| quote | string | props.Text() |
| authorName | string | props.Text() |
| authorTitle | string (optionnel) | props.Text() |
| rating | number (optionnel) | props.Number() |
### Problèmes détectés :
- **Classe CSS « testimonial-card »** - Utilise classe globale qui ne fonctionnera pas en Shadow DOM
- Correction : Convertir en CSS Modules ou importer styles limités
### Aucun problème bloquant - prêt à convertir !
---
## Fichiers générés
### 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
}
});
Modifications requises pour TestimonialCard.tsx
- Convertir en CSS Modules - Renommer
TestimonialCard.cssenTestimonialCard.module.csset mettre à jour imports :
import styles from "./TestimonialCard.module.css";
// CSS Modules par défaut utilise notation crochet :
<div className={styles["testimonial-card"]}>
<div className={styles["stars"]}>
// Notation pointée (styles.testimonialCard) nécessite noms de classe camelCase
// ou override webpack pour css-loader.
Vérification de la configuration
- [ ] Vérifier que webflow.json existe
- [ ] Installer dépendances si nécessaire :
npm i --save-dev @webflow/webflow-cli @webflow/data-types @webflow/react
Exemple 2 : Composant avec motifs incompatibles
Demande utilisateur :
Make this work as a Webflow code component:
// 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<ModalProps> = ({ 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 }}>
<div onClick={toggle}>{trigger}</div>
{isOpen && (
<div className="modal-overlay" onClick={toggle}>
<div className="modal-content" onClick={e => e.stopPropagation()}>
{children}
</div>
</div>
)}
</ModalContext.Provider>
);
};
Réponse :
## Analyse du composant : Modal
### Problèmes détectés :
| Problème | Sévérité | Résolution |
|----------|----------|-----------|
| React Context (ModalContext) | Critique | Context ne fonctionnera pas entre les composants Webflow. Puisque c'est interne à Modal, c'est OK mais hook useModal exporté ne fonctionnera pas. |
| Manipulation de document.body | Critique | Incompatible SSR. Doit définir `ssr: false` ou envelopper dans vérification useEffect. |
| Callbacks onOpen/onClose | Avertissement | Props de fonction non supportées dans Webflow. Doit supprimer. |
| Classes CSS globales | Avertissement | « modal-overlay », « modal-content » ne fonctionneront pas en Shadow DOM. |
### Props détectés :
| Prop | Type TypeScript | Mappage Webflow | Statut |
|------|-----------------|-----------------|--------|
| trigger | React.ReactNode | props.Slot() | OK |
| children | React.ReactNode | props.Slot() | OK |
| onOpen | function | SUPPRIMER | Non supporté |
| onClose | function | SUPPRIMER | Non supporté |
---
## Modifications requises
### 1. Supprimer les props de fonction (onOpen, onClose)
Celles-ci ne peuvent pas être passées depuis Webflow Designer. Supprimer de l'interface et du composant.
### 2. Corriger le problème SSR avec document.body
Soit définir `ssr: false` soit ajouter vérification typeof :
```typescript
useEffect(() => {
if (typeof document === 'undefined') return;
// ... reste de l'effet
}, [isOpen]);
3. Convertir en CSS Modules
Renommer styles et mettre à jour références de classe.
4. Supprimer hook useModal exporté
Cela ne fonctionnera pas pour les composants externes. Garder ModalContext interne seulement.
Fichiers générés
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 mis à jour
import { useState, useEffect } from 'react';
import styles from "./Modal.module.css";
interface ModalProps {
trigger: React.ReactNode;
children: React.ReactNode;
// Supprimé : onOpen, onClose - non supporté dans 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>
)}
</>
);
};
Configuration requise
npm i --save-dev @webflow/webflow-cli @webflow/data-types @webflow/react
---
### Exemple 3 : Composant avec props d'objet complexe
**Demande utilisateur :**
Convert to 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) => ( <div> <img src={product.image} alt={product.name} /> {showBadge && <span>{product.category}</span>} <h3>{product.name}</h3> <p>${product.price}</p> </div> );
**Réponse :**
```markdown
## Analyse du composant : ProductCard
### Props complexes détectés :
Le prop `product` est un objet complexe qui doit être aplati pour Webflow :
| Original | Props aplatis |
|----------|---------------|
| product.id | (Non nécessaire en UI - supprimer) |
| product.name | productName: props.Text() |
| product.price | productPrice: props.Number() |
| product.image | productImage: props.Image() |
| product.category | productCategory: props.Variant() |
| showBadge | showBadge: props.Boolean() |
---
## Fichiers générés
### 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 mis à jour
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>
);
Notes de migration :
- L'objet
producta été aplati en props individuels - Chaque prop est maintenant directement éditable dans Webflow Designer
product.ida été supprimé car non affiché dans l'UI- Prop Image utilise maintenant le type Image Webflow (fournit { src, alt })
Exemple 4 : Composant avec styled-components
Demande utilisateur :
Convert this styled-components React component to 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) => (
<StyledButton variant={variant} disabled={disabled}>
{label}
</StyledButton>
);
Réponse :
## Analyse du composant : Button
### Approche de style détectée : styled-components
styled-components nécessite un décorateur Shadow DOM pour fonctionner dans Webflow.
### Props détectés :
| Prop | Type TypeScript | Mappage Webflow |
|------|-----------------|-----------------|
| label | string | props.Text() |
| variant | 'primary' \| 'secondary' | props.Variant() |
| disabled | boolean | props.Boolean() |
### Aucun problème bloquant - prêt à convertir !
---
## Configuration requise pour styled-components
**1. Installer dépendances :**
```bash
npm i @webflow/styled-components-utils styled-components
npm i -D @types/styled-components
2. Créer/mettre à jour src/globals.ts :
import { styledComponentsShadowDomDecorator } from "@webflow/styled-components-utils";
export const decorators = [styledComponentsShadowDomDecorator];
3. Mettre à jour webflow.json :
{
"library": {
"name": "My Library",
"components": ["./src/**/*.webflow.@(js|jsx|mjs|ts|tsx)"],
"globals": "./src/globals.ts"
}
}
Fichiers générés
Button.webflow.tsx
import { declareComponent } from "@webflow/react";
import { props } from "@webflow/data-types";
import { Button } from "./Button";
// Aucun import CSS nécessaire - styled-components gère les 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
}
});
Aucune modification nécessaire pour Button.tsx
Le composant peut rester tel quel. Le décorateur styled-components dans globals.ts gèrera l'injection de style Shadow DOM automatiquement.
Checklist de configuration
- [ ] Installer @webflow/styled-components-utils
- [ ] Créer globals.ts avec décorateur
- [ ] Mettre à jour webflow.json pour référencer globals
- [ ] Déployer avec
npx webflow library share
Directives
Quand recommander refonte de composant
Certains composants ne correspondent fondamentalement pas au modèle Webflow :
- Utilisation importante de Context : Si le composant repose sur context au niveau application, suggérer refonte
- Machines d'état complexes : Peut nécessiter simplification
- Composants étroitement couplés : Chacun doit être indépendant dans Webflow
- Composants qui rendent des portals : Considérer si portal est nécessaire
Stratégie de valeur par défaut
Toujours fournir défauts sensés :
- Props texte : Texte d'exemple représentatif
- Nombres : Valeur commune/typique
- Booléens : Cas d'utilisation le plus courant
- Variantes : Option la plus populaire
- Images : Peut être indéfini (optionnel)
- Slots : Pas de défaut nécessaire
Nommage des props pour Webflow
Rendre noms de props designer-friendly :
- Utiliser noms descriptifs :
buttonTextplutôt quetxt - Éviter abréviations :
imageSourceplutôt queimgSrc - Grouper props associés avec préfixes :
authorName,authorAvatar,authorBio
Décision SSR
Définir ssr: false si le composant :
- Accède à
window,document,navigator - Utilise
localStorageousessionStorage - Manipule le DOM directement
- Utilise bibliothèques nécessitant APIs du navigateur
- Rend canvas, WebGL ou cartes