Skip to main content

Component Not Selectable

You may notice an info icon next to a component in Weaverse Studio’s outline panel. This indicates that Studio cannot locate the component’s DOM element in the preview.
Weaverse Studio showing an info icon on a component that is not selectable in the preview
Don’t worry — your component is still fully editable. You can always select it from the outline panel and modify its settings. The info icon simply means Studio can’t highlight or select it by clicking directly on the preview.

Why This Happens

Weaverse Studio identifies components in the preview by looking for a data-wv-id attribute on the DOM element. This attribute is automatically included in the props that Weaverse passes to your component. There are three common causes for this:
  1. Props not spread correctly — the data-wv-id attribute is in the props but never reaches the DOM
  2. Component returns null — no DOM element is rendered at all, so there’s nothing for Studio to find
  3. Component is conditionally rendered — a parent component controls whether this component appears in the DOM

How to Fix

Cause 1: Props Not Spread Correctly

When your component doesn’t spread the remaining props (...rest) onto its root DOM element, the data-wv-id attribute never reaches the DOM. Studio can see the component exists in the data layer, but it cannot find the corresponding element in the preview.
1

Destructure your custom props from the rest

Separate your component-specific props and children from everything else using the spread operator:
function MySection(props: MySectionProps) {
  const { heading, description, children, ...rest } = props;
  // ...
}
2

Spread the remaining props onto the root DOM element

Pass ...rest to the outermost HTML element. This ensures data-wv-id and all other Weaverse-internal attributes reach the DOM:
function MySection(props: MySectionProps) {
  const { heading, description, children, ...rest } = props;

  return (
    <section {...rest}>
      <h2>{heading}</h2>
      <p>{description}</p>
      {children}
    </section>
  );
}
3

Restart the development server

After making changes, restart your dev server to pick up the updated component:
npm run dev

Before & After

// app/sections/my-section/index.tsx
function MySection(props: MySectionProps) {
  // Only destructured custom props — rest of props are lost
  const { heading, description } = props;

  return (
    // data-wv-id and other Weaverse props are lost
    <section>
      <h2>{heading}</h2>
      <p>{description}</p>
    </section>
  );
}
If you’re using forwardRef, the same rule applies — spread ...rest and pass the ref:
import { forwardRef } from "react";

const MySection = forwardRef<HTMLElement, MySectionProps>((props, ref) => {
  const { heading, description, children, ...rest } = props;

  return (
    <section ref={ref} {...rest}>
      <h2>{heading}</h2>
      <p>{description}</p>
      {children}
    </section>
  );
});

export default MySection;
With React 19, forwardRef becomes less necessary. If you spread all props (including ref) onto the root element, Weaverse can detect the DOM element automatically. See the Weaverse Component guide for more details.

Cause 2: Component Returns null

If your component conditionally returns null, no DOM element is rendered at all. Without a DOM element, there’s no place for the data-wv-id attribute to exist, and Studio cannot locate or select the component. This commonly happens when components guard against missing data.
1

Find the early return

Look for any return null statements in your component, especially conditional guards at the top:
function FeaturedProduct(props: FeaturedProductProps) {
  const { loaderData, children, ...rest } = props;
  const product = loaderData?.product;

  // This is the problem — no DOM element when product is missing
  if (!product) {
    return null;
  }

  return (
    <section {...rest}>
      <h2>{product.title}</h2>
      {children}
    </section>
  );
}
2

Always render a root element with props spread

Replace the return null with an empty self-closing element that spreads ...rest:
function FeaturedProduct(props: FeaturedProductProps) {
  const { loaderData, children, ...rest } = props;
  const product = loaderData?.product;

  if (!product) {
    return <section {...rest} />;
  }

  return (
    <section {...rest}>
      <h2>{product.title}</h2>
      {children}
    </section>
  );
}
3

Restart the development server

After making changes, restart your dev server to pick up the updated component:
npm run dev

Before & After

function FeaturedProduct(props: FeaturedProductProps) {
  const { loaderData, children, ...rest } = props;
  const product = loaderData?.product;

  if (!product) return null;

  return (
    <section {...rest}>
      <h2>{product.title}</h2>
      {children}
    </section>
  );
}
Avoid returning null from a Weaverse component. Render at least a root element with {...rest} so Studio can locate it in the preview. Use conditional rendering inside the root element instead.

Common Patterns That Cause This

Watch out for any conditional return before the root element:
// All of these prevent the root element from rendering
if (!data) return null;
if (items.length === 0) return null;
if (!isEnabled) return null;
if (loading) return null;
Instead, move the condition inside the root element:
return (
  <section {...rest}>
    {!data ? <Placeholder /> : <Content data={data} />}
  </section>
);
This is a subtler version of the same problem:
// Wrong
return isVisible ? (
  <section {...rest}>{children}</section>
) : null;

// Correct
return (
  <section {...rest}>
    {isVisible ? children : null}
  </section>
);

Cause 3: Component Is Conditionally Rendered

Sometimes the component itself is fine, but a parent component decides whether to render it based on some condition. When the condition is false, the child component is removed from the DOM entirely, and Studio can’t find it in the preview. This is standard conditional rendering in React — nothing is broken.
function ParentSection(props: ParentSectionProps) {
  const { showBanner, children, ...rest } = props;

  return (
    <section {...rest}>
      {/* When showBanner is false, BannerChild is not in the DOM */}
      {showBanner && children}
    </section>
  );
}
In this case, the child component will show an info icon in the outline panel whenever showBanner is false. This is expected behavior — when the parent renders the child again, it becomes selectable in the preview automatically.
You don’t need to fix this. It’s a natural result of conditional rendering. The child component is always editable via the outline panel regardless of whether it’s visible in the preview.

Checklist

If a component shows an info icon in Studio, verify:
  • The component destructures custom props and captures ...rest
  • ...rest is spread onto the root DOM element
  • The component never returns null — return an empty element with {...rest} instead
  • If conditionally rendered by a parent — this is expected and safe, no action needed
  • The development server has been restarted after changes