> Portal Navigation:
> 
> - Append `.md` to any URL under `https://dev.wix.com/docs/` to get its markdown version.
> - Pages are either content pages (article or reference text) or menu pages (a list of links to child pages).
> - To get a menu page, truncate any URL to a parent path and append `.md` (e.g. `https://dev.wix.com/docs/sdk.md`, `https://dev.wix.com/docs/sdk/core-modules.md`).
> - Top-level index of all portals: https://dev.wix.com/docs/llms.txt
> - Full concatenated docs: https://dev.wix.com/docs/llms-full.txt

## Resource: Build an Editor React Component in Studio Two

## Article: Build an Editor React Component in Studio Two

## Article Link: https://dev.wix.com/docs/studio-two/code-your-site/code-model/editor-react-components/build-an-editor-react-component-in-studio-two.md

## Article Content:

# Build an Editor React Component in Studio Two

An [Editor React Component (ERC)](https://dev.wix.com/docs/studio-two/code-your-site/code-model/editor-react-components/about-editor-react-components.md) is built component first. You write the React code, the prop types, and the CSS, and then you regenerate the `editorElement` portion of the manifest from those three files. What a Wix user can select, edit, and style in the editor follows from how you write them.

This article walks through that loop end to end, from a scaffolded component to one with its own panels, presets, and states. The examples build a testimonial card with a quote and an author name.

Follow the instructions below to:

1. Scaffold the component.
2. Build the component UI.
3. Set props and defaults.
4. Style the component.
5. Regenerate and check the manifest.
6. Refine the manifest.
7. Add presets and states.
8. Check the component in the editor.

## Step 1 | Scaffold the component

Start from a generated ERC rather than an empty folder, so the file structure and registration are already in place. For the procedure, see [Add an Editor React Component Extension in Studio Two](https://dev.wix.com/docs/studio-two/code-your-site/code-model/editor-react-components/add-an-editor-react-component-extension-in-studio-two.md).

You can find the new files under `src/extensions/site/components/<component-folder>/`. You spend most of this article in these files:

- `<component-folder>.tsx`
- `<component-folder>.props.ts`
- `<component-folder>.module.css`
- `<component-folder>.extension.ts`

You also update `component.preview.tsx` once, in Step 3. Leave `component.tsx` as generated. For what every file in the folder is for, see [Editor React Component Extension Files and Code](https://dev.wix.com/docs/site-extensions/editor-react-components/editor-react-component-extension-files-and-code.md).

To save a file, press `Control+S` (or `Command+S` on macOS). A circle on a file's tab means the file has unsaved edits. When the status bar shows Synced, the editor has your saved changes.

<blockquote class="tip">

__Tip:__ If the status bar shows that the sync failed, click it to retry. If it keeps syncing for a long time, reload the editor.

</blockquote>

## Step 2 | Build the component UI

Write your JSX in `<component-folder>.tsx`. Two rules govern how the editor sees it.

First, the root element carries the `id` and `className` props Wix passes in, plus a plain string class that the manifest `selector` matches. Without both the `id` and a matching class, the component renders but a Wix user can't select it or open its panels. Name the root class after the component so it doesn't collide with anything else on the page.

Second, every element you want the editor to target needs a plain string class alongside its CSS Module class. CSS Modules rewrite class names at build time, so a module class alone never matches a manifest selector. Give structural wrappers a module class only, and the editor leaves them alone.

For the example, `.testimonial-card` is the root selector, and `.testimonial-quote` and `.testimonial-author` mark the inner elements. The scaffold uses `clsx` to combine class names, so the example does too:

```tsx
import React from 'react';
import type { FC } from 'react';
import clsx from 'clsx';
import styles from './testimonial-card.module.css';
import type { TestimonialCardProps } from './testimonial-card.props';

const TestimonialCard: FC<TestimonialCardProps> = ({
  id,
  className,
  quote,
  authorName,
}) => {
  return (
    <div id={id} className={clsx('testimonial-card', styles.card, className)}>
      <blockquote className={clsx('testimonial-quote', styles.quote)}>
        {quote}
      </blockquote>
      <p className={clsx('testimonial-author', styles.author)}>{authorName}</p>
    </div>
  );
};

export default TestimonialCard;
```

For the full DOM contract, including selector length limits and the props Wix provides, see [Component Requirements](https://dev.wix.com/docs/site-extensions/editor-react-components/component-requirements.md) and [Runtime Props Reference](https://dev.wix.com/docs/site-extensions/editor-react-components/manifest-reference/runtime-props-reference.md).

## Step 3 | Set props and defaults

Declare your props type and a `defaultProps` constant in `<component-folder>.props.ts`. Each prop you declare becomes editable content in the editor, and the value a Wix user sets arrives back on the component as that same prop at runtime.

Set each default once, in this file. It feeds both the rendered component and the editor panels, so the controls open on the same values a Wix user sees on the canvas. A copy of the component that's already on a page keeps the values it was added with, so a changed default shows only on copies added after you save. Leave `id` and `className` out of `defaultProps`, because Wix always supplies them.

For the example, the props replace the scaffold's `image`, `title`, `description`, and `direction`:

```ts
export type TestimonialCardProps = {
  id: string;
  className?: string;
  quote?: string;
  authorName?: string;
};

export const defaultProps = {
  quote: 'This team delivered beyond what we expected.',
  authorName: 'Alex Rivera',
} as const satisfies Omit<TestimonialCardProps, 'id' | 'className'>;
```

### Update the preview's required fields

When you rename or replace props, update `component.preview.tsx` to match. That file is what the editor canvas loads. The scaffold wraps the component in `withFallbackPlaceholder` with a `requiredDataFields` list that names the scaffold's `title` and `description` props. If a field in that list is missing from the component's props, the canvas shows a placeholder instead of the component.

List your own content props in `requiredDataFields`, not `id` or `className`. For the example:

```tsx
const TestimonialCardPreviewWithFallback = withFallbackPlaceholder(TestimonialCardPreview, {
  requiredDataFields: ['quote', 'authorName'],
  rootClassName: 'testimonial-card',
});
```

## Step 4 | Style the component

Write default styles in `<component-folder>.module.css`. CSS Modules scope the class names to your component, so they can't collide with other components on the page.

The CSS properties you set here are what the editor turns into design controls. A property you never style isn't offered to Wix users.

For the example:

```css
.card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 24px;
  background-color: #ffffff;
  border-radius: 8px;
}

.quote {
  font-size: 16px;
}

.author {
  font-size: 14px;
}
```

These scoped class names aren't what the manifest matches. Keep the plain string classes from Step 2 on every element the editor targets.

## Step 5 | Regenerate and check the manifest

The `editorElement` in `<component-folder>.generated.ts` is the part of the manifest that declares editable data, inner elements, CSS properties, presets, states, and layout. The editor builds its panels from it. After you change the component, its props, or its CSS, regenerate the manifest.

To regenerate the manifest:

1. In the **Code** tab, open the terminal. Press `Control+J` (or `Command+J` on macOS).
2. Run:

   ```bash
   npx wix build && npx wix generate manifest
   ```

Then open `<component-folder>.generated.ts` and read it as a report on what you wrote:

- Each prop becomes an entry under `data`. A Wix user edits text props in the component's **Edit Text** panel.
- Each element with a plain string class becomes an entry under `elements`. Generated entries set `inlineElement.behaviors.selectable` to `false`, so a Wix user can't select those elements on their own. Step 6 covers changing that.
- Each CSS property you styled becomes a `cssProperties` entry that the editor can offer as a design control.

If something you expected is missing, fix it in the source files and regenerate. A control that doesn't appear usually means a prop wasn't declared or a property was never styled. An element missing from `elements` usually has a module class but no plain string class.

Don't edit `<component-folder>.generated.ts`. Your changes are overwritten the next time you regenerate the manifest.

For what each manifest property controls in the editor, see [About Auto Panels for Editor React Components](https://dev.wix.com/docs/site-extensions/editor-react-components/about-auto-panels-for-editor-react-components.md).

## Step 6 | Refine the manifest

`<component-folder>.extension.ts` is the manifest you own. Regenerating never overwrites it, so this is where you adjust anything the generated `editorElement` got wrong or left bare.

The scaffold merges your overrides onto the generated `editorElement` with `deepmerge`. Add each override to the second object, which already holds the scaffold's `layout` settings. You only write the values you change:

```ts
editorElement: deepmerge(
  editorElementWithDefaults,
  {
    layout: {
      resizeDirection: LAYOUT.RESIZE_DIRECTION.horizontalAndVertical,
      contentResizeDirection: LAYOUT.CONTENT_RESIZE_DIRECTION.vertical,
    },
  }
),
```

Common refinements:

- **Label controls.** Set `displayName` on data items, CSS properties, and elements so panels read in your words instead of your variable names.
- **Make inner elements selectable.** Under `elements`, use the element's key from the generated file and set `inlineElement.behaviors.selectable` to `true`. The element then gets its own action bar and panels. For every element field, see [Elements](https://dev.wix.com/docs/site-extensions/editor-react-components/editor-element/elements.md).
- **Group controls.** Use `displayGroups` to collect related properties into named sections inside a panel.
- **Show controls conditionally.** Use `displayFilters` to hide a control unless another data item, preset, or state calls for it.
- **Set sizing behavior.** Use `layout` for resize and stretch behavior, and `installation.initialSize` for the size the component takes when a Wix user first adds it to a page.

This file also holds the component's identity and its resources. For every field, see [About the Editor React Component Manifest](https://dev.wix.com/docs/site-extensions/editor-react-components/manifest-reference/about-the-editor-react-component-manifest.md).

<blockquote class="important">

__Important:__ Some type properties are immutable once the manifest is saved for the first time, including `dataType` on a data item and `elementType` on an element. Changing one later fails validation and blocks deployment. To use a different type, add a new variable with the type you want instead of editing the existing one.

</blockquote>

## Step 7 | Add presets and states

Presets and states are the two things a Wix user gets that don't come from your base declarations. You declare both in `editorElement`, inside the object you pass to `deepmerge()` in `<component-folder>.extension.ts`, as in Step 6, so regenerating the manifest never overwrites them. Each one also needs a small change in the component and its CSS. The sections below show what to add to which file.

### Presets

A preset is a named visual variation of your component, such as a card layout and a minimal layout. Declaring `presets` gives the component an **Explore Designs** panel, where switching variation is a single click. To open it, select the component on the canvas and click the **Explore Designs** icon in the bottom action bar, to the left of the state selector.

**1. `<component-folder>.tsx`:** Wrap the root element in a container and spread `wix.presetsWrapperProps` onto it. Keep `id` and `className` on the inner element, not on the wrapper.

```tsx
import React from 'react';
import type { FC } from 'react';
import clsx from 'clsx';
import type { Wix } from '@wix/editor-react-types';
import styles from './testimonial-card.module.css';
import type { TestimonialCardProps } from './testimonial-card.props';

const TestimonialCard: FC<TestimonialCardProps & { wix?: Wix }> = ({
  id,
  className,
  quote,
  authorName,
  wix,
}) => {
  return (
    <div {...(wix?.presetsWrapperProps || {})}>
      <div id={id} className={clsx('testimonial-card', styles.card, className)}>
        <blockquote className={clsx('testimonial-quote', styles.quote)}>
          {quote}
        </blockquote>
        <p className={clsx('testimonial-author', styles.author)}>{authorName}</p>
      </div>
    </div>
  );
};

export default TestimonialCard;
```

**2. `<component-folder>.extension.ts`:** Add `presets` inside the object you pass to `deepmerge()`, and set `installation.presets` to choose the starting preset at each breakpoint. Each preset needs a `thumbnailUrl` for the panel and a `presetCssUrl` for the CSS the editor applies when it's selected.

```ts
editorElement: deepmerge(editorElementWithDefaults, {
  presets: {
    card: {
      displayName: 'Card',
      thumbnailUrl: 'https://static.example.com/testimonial-card/card.png',
      presetCssUrl: 'https://static.example.com/testimonial-card/card.css',
    },
    minimal: {
      displayName: 'Minimal',
      thumbnailUrl: 'https://static.example.com/testimonial-card/minimal.png',
      presetCssUrl: 'https://static.example.com/testimonial-card/minimal.css',
      styleOverrides: {
        default: {
          cssProperties: {
            background: { value: '#fff3cd' },
          },
        },
      },
    },
  },
}),
installation: {
  presets: {
    default: 'card',
    small: 'card',
  },
  // ...
},
```

Replace the example URLs with your own. The thumbnail and CSS URLs must be publicly reachable.

To change a value when a Wix user picks a preset, use one of two fields. Use `presetDefaults` for the values that apply when a Wix user switches to the preset, such as layout behavior, CSS property defaults, and nested element defaults. Use `styleOverrides` when a value has to change by breakpoint or by state, such as a smaller font size on mobile. In the example, selecting **Minimal** in **Explore Designs** changes the card's background to `#fff3cd`.

<blockquote class="important">

__Important:__ Every CSS property or element key you reference in `presetDefaults` or `styleOverrides` must already exist in the component's `editorElement`. If one doesn't, the editor reports "One or more referenced keys do not exist" under **Site code errors**, and the component stops loading on the canvas. Check the key names in `<component-folder>.generated.ts` first. For example, a `background-color` declaration in your CSS appears there as `background`, so `backgroundColor` isn't a valid key.

</blockquote>

For every preset field and worked examples, see [Presets](https://dev.wix.com/docs/site-extensions/editor-react-components/editor-element/presets/presets.md).

### States

A state is a condition a Wix user styles separately, such as hover or loading. Declaring `states` adds a state selector to the bottom action bar. To find it, select the component on the canvas. The selector is the drop-down that reads **Regular**, next to **Edit Text**. Choosing a state, such as **Hover**, shows the component in that state on the canvas, and the design controls you change apply to that state.

**1. `<component-folder>.extension.ts`:** Add `states` inside the object you pass to `deepmerge()`. How you declare each state depends on where it comes from:

- Use `pseudoClass` for states the browser handles on the live site, such as hover or disabled. Set it to a `NATIVE_STATE_TYPE` value, imported from `@wix/react-component-schema`. A plain string such as `'hover'` fails type checking.
- Use `className` for custom states with no pseudo-class equivalent, such as loading or selected. The editor applies this class to the component while the state is selected.
- Use `props` to put the component into that state on the editor canvas, so a Wix user can see what they're styling.

```ts
import { NATIVE_STATE_TYPE } from '@wix/react-component-schema';

// ...

editorElement: deepmerge(editorElementWithDefaults, {
  states: {
    hover: {
      displayName: 'Hover',
      pseudoClass: NATIVE_STATE_TYPE.hover,
      className: 'testimonial-card-hover',
    },
  },
}),
```

**2. `<component-folder>.module.css`:** Write the styles for the state. Target both the pseudo-class, for the live site, and the state's class, for the editor canvas. Because CSS Modules rewrite class names, wrap the state class in `:global()`.

```css
.card:hover,
.card:global(.testimonial-card-hover) {
  background-color: #f5f5f5;
}
```

**3. (Optional) `<component-folder>.extension.ts`, on a CSS property:** To give a property a different default under a state, add `statesDefaultValues` to that property in the object you pass to `deepmerge()`. Use the property's key from `<component-folder>.generated.ts`, and key each value by the state's name.

```ts
editorElement: deepmerge(editorElementWithDefaults, {
  cssProperties: {
    background: {
      statesDefaultValues: {
        hover: '#e8f0fe',
      },
    },
  },
}),
```

When a Wix user selects **Hover** in the state selector, the background control then starts from `#e8f0fe` instead of the regular value.

For every state field and worked examples, see [States](https://dev.wix.com/docs/site-extensions/editor-react-components/editor-element/states.md).

## Step 8 | Check the component in the editor

To check your component:

1. Switch to the **Design** tab.
2. Navigate to **Add Elements > AI Generated**.
3. Select your component to place it on the page. If it isn't listed, ask **Aria**, Wix's AI assistant, to place it for you. For how to work with Aria, see [Working with Aria](https://support.wix.com/en/article/wix-studio-20-working-with-aria). Add a fresh copy after each round of changes, because a copy placed earlier keeps the prop values it was added with.
4. Confirm that the component shows your default prop values. If the canvas shows a placeholder instead, check the `requiredDataFields` list from Step 3, then regenerate the manifest as in Step 5.
5. Select the component and open each control on its action bar. Confirm that **Edit Text** lists each text prop with its default value.
6. If you made inner elements selectable in Step 6, click each one and confirm it has its own action bar.
7. (Optional) Click **Preview** to view the page outside edit mode.

Panels that don't look right point back to a specific file. Missing or misnamed controls are a manifest matter, so return to Step 5 or Step 6. Controls that exist but don't change anything on the canvas usually mean a selector doesn't match a class the component renders, so return to Step 2.

When the component behaves the way you want, click **Publish** to ship it with the site.

## See also

- [About Editor React Components](https://dev.wix.com/docs/studio-two/code-your-site/code-model/editor-react-components/about-editor-react-components.md)
- [Add an Editor React Component Extension in Studio Two](https://dev.wix.com/docs/studio-two/code-your-site/code-model/editor-react-components/add-an-editor-react-component-extension-in-studio-two.md)
- [Use a Wix Context in an Editor React Component in Studio Two](https://dev.wix.com/docs/studio-two/code-your-site/code-model/editor-react-components/use-a-wix-context-in-an-editor-react-component-in-studio-two.md)
- [Editor React Component Extension Files and Code](https://dev.wix.com/docs/site-extensions/editor-react-components/editor-react-component-extension-files-and-code.md)
- [Component Requirements](https://dev.wix.com/docs/site-extensions/editor-react-components/component-requirements.md)
- [About the Editor React Component Manifest](https://dev.wix.com/docs/site-extensions/editor-react-components/manifest-reference/about-the-editor-react-component-manifest.md)