> ## Documentation Index
> Fetch the complete documentation index at: https://beta.docs.replo.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Site Components

> Reuse one header, footer, or section across pages, and preview and customize it in one place.

export const TryPromptButton = ({prompt, imageSrc, imageAlt = "Template preview", imageStyles = {}, buttonCta = "Build in Replo"}) => {
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);
  const PUBLISHER_API_BASE_URL = "https://publisher.replo.app";
  const APP_URL = "https://dashboard.replo.app";
  const LoaderIcon = <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{
    animation: "spin 1s linear infinite"
  }}>
      <path d="M21 12a9 9 0 1 1-6.219-8.56" />
    </svg>;
  const ChevronIcon = <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <path d="m9 18 6-6-6-6" />
    </svg>;
  async function postJSON(url, body, headers = {}, timeoutMs = 120000) {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
    try {
      const response = await fetch(url, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          ...headers
        },
        body: JSON.stringify(body ?? ({})),
        signal: controller.signal
      });
      const responseText = await response.text();
      if (!response.ok) throw new Error(`API Error: ${response.status}`);
      return responseText ? JSON.parse(responseText) : {};
    } finally {
      clearTimeout(timeoutId);
    }
  }
  async function handleTryPrompt(event) {
    event.preventDefault();
    event.stopPropagation();
    setIsLoading(true);
    setError(null);
    try {
      const body = {
        prompt,
        file: null
      };
      const {seed} = await postJSON(`${PUBLISHER_API_BASE_URL}/api/v1/marketing/issue-marketing-site-jwt`, body);
      if (!seed) throw new Error("No seed returned from API");
      const url = new URL(APP_URL);
      url.searchParams.set("type", "agent");
      url.hash = `seed=${encodeURIComponent(seed)}`;
      window.open(url.toString(), "_blank");
    } catch (caughtError) {
      console.error("Failed to generate prompt:", caughtError);
      setError("Something went wrong. Please try again.");
    } finally {
      setIsLoading(false);
    }
  }
  return <div style={{
    position: "relative",
    display: "inline-block",
    width: "100%"
  }}>
      {}
      {imageSrc && <img src={imageSrc} alt={imageAlt} style={{
    width: "100%",
    height: "auto",
    display: "block",
    borderRadius: "8px",
    opacity: 0.8,
    ...imageStyles
  }} />}

      {}
      <div style={imageSrc ? {
    position: "absolute",
    top: "50%",
    left: "50%",
    transform: "translate(-50%, -50%)",
    zIndex: 10
  } : {
    display: "flex",
    justifyContent: "flex-start",
    margin: "1.25rem 0"
  }}>
        <button type="button" className="try-replo-btn" onClick={handleTryPrompt} disabled={isLoading} style={{
    backgroundColor: "#274AE2",
    color: "#ffffff",
    padding: "0.5rem 1.1rem",
    fontSize: "0.875rem",
    fontWeight: 600,
    fontFamily: "inherit",
    border: "none",
    borderRadius: "9999px",
    cursor: isLoading ? "not-allowed" : "pointer",
    lineHeight: 1.4,
    whiteSpace: "nowrap",
    display: "inline-flex",
    alignItems: "center",
    justifyContent: "center",
    WebkitFontSmoothing: "antialiased",
    boxSizing: "border-box",
    opacity: isLoading ? 0.7 : 1,
    boxShadow: "0 1px 2px rgba(15, 23, 42, 0.08)",
    transition: "background-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease"
  }}>
          <span style={{
    visibility: isLoading ? "hidden" : "visible",
    display: "inline-flex",
    alignItems: "center",
    gap: "0.375rem"
  }}>
            {buttonCta}
            {ChevronIcon}
          </span>
          {isLoading && <span style={{
    position: "absolute",
    display: "inline-flex",
    alignItems: "center",
    justifyContent: "center"
  }}>
              {LoaderIcon}
            </span>}
        </button>
      </div>

      {}
      <style>
        {`
          @keyframes spin {
            from {
              transform: rotate(0deg);
            }
            to {
              transform: rotate(360deg);
            }
          }
          .try-replo-btn:hover:not(:disabled) {
            background-color: #1f3ec0 !important;
            box-shadow: 0 4px 12px rgba(39, 74, 226, 0.35);
            transform: translateY(-1px);
          }
          .try-replo-btn:active:not(:disabled) {
            transform: translateY(0);
            box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);
          }
          .try-replo-btn:focus-visible {
            outline: 2px solid #274AE2;
            outline-offset: 2px;
          }
        `}
      </style>

      {}
      {error && <div style={{
    marginTop: "12px",
    padding: "12px 16px",
    backgroundColor: "#fee",
    border: "1px solid #fcc",
    borderRadius: "6px",
    color: "#c33",
    fontSize: "14px",
    textAlign: "center"
  }} role="alert">
          {error}
        </div>}
    </div>;
};

Site Components are the pieces of your site that repeat across pages: the header, the footer, an announcement bar, a testimonial card. Each one lives in one place, so a change applies everywhere it's used instead of drifting page by page.

Open them from the [Site Builder](/apps/website-builder): on your site's dashboard, click **Site Components** in the top bar (next to **Site Settings**).

## Create a component

Ask Replo in chat. The most common way is pointing at something that already exists on a page:

```text theme={null}
Use the same header as my home page on the new landing page.
```

<TryPromptButton prompt="Use the same header as my home page on the new landing page." />

Replo extracts the header into your site's component library, keeps the original page looking exactly the same, and reuses it on the page you asked for. You can also be explicit:

```text theme={null}
Turn my home page header into a component and use it on every page.
```

<TryPromptButton prompt="Turn my home page header into a component and use it on every page." />

Or build one from scratch:

```text theme={null}
Make an announcement bar component with editable text and a link.
```

<TryPromptButton prompt="Make an announcement bar component with editable text and a link." />

## Preview and customize

In **Site Components**, pick a component to see it rendered on its own, away from any page. The panel on the right lists its options: text, toggles, layout choices, and, for product components, a picker that previews the component with any product from your store.

Changes in the panel preview instantly, so use it to explore variations. The panel doesn't change your site; when you find a version you want to keep, tell Replo:

```text theme={null}
Make the centered layout the default for my header.
```

<TryPromptButton prompt="Make the centered layout the default for my header." />

## Edit a component

Mention the component in chat with **@**, or just name it ("update my footer"). Because pages share one implementation, a single edit updates every page that uses it, and Replo tells you which pages changed.

If you want a change on only one page, say so. Replo adds an option to the component and applies it just there, so the other pages keep their current look.

## FAQ

<AccordionGroup>
  <Accordion title="Why doesn't a section of my page show up in Site Components?">
    Only components saved to your site's component library appear. Sections built directly into a page belong to that page. Ask Replo to "save this section as a component" and it moves into the library.
  </Accordion>

  <Accordion title="What does &#x22;Preview needs an update&#x22; mean?">
    Your site needs a newer setup to render component previews. Ask Replo to update this site, then come back to Site Components.
  </Accordion>

  <Accordion title="Do changes I make in the options panel go live?">
    No. The panel is a preview, so you can try variations safely. To keep a version, ask Replo to make it the default, and publish as usual for it to go live.
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Select mode" href="/features/edit-mode">
    Click an element on a page and ask Replo to change exactly that.
  </Card>

  <Card title="Building pages with AI" href="/features/building-pages-ai">
    Compose pages from sections, then promote the ones worth reusing.
  </Card>

  <Card title="Publishing" href="/publishing">
    Publish so component changes go live.
  </Card>
</CardGroup>
