Frequently Asked Questions

Click to Edit & Preview SDK Implementation

How do I implement Click to Edit in a Next.js App Router project using Hygraph?

To implement Click to Edit, install the @hygraph/preview-sdk package, create a PreviewWrapper component, and wrap your application content at the layout level. Add data-hygraph-* attributes to elements rendering Hygraph field values. For full steps and code examples, see the Click to Edit Next.js guide. Note: The wrapper must be applied at the layout level for the SDK to register page content. Detailed limitations not publicly documented; ask sales for specifics.

What configuration properties are required for the Hygraph Preview SDK?

The Preview SDK requires endpoint (Hygraph Content API endpoint) and studioUrl (your project's custom Studio domain). Optional properties include debug, mode, onSave, overlay, sync.fieldFocus, sync.fieldUpdate, and allowedOrigins. For details, see the documentation. Note: If studioUrl ends with a trailing slash, Click to Edit will fail in standalone mode.

How do I set up environment variables for Click to Edit functionality?

Add NEXT_PUBLIC_HYGRAPH_ENDPOINT, NEXT_PUBLIC_HYGRAPH_STUDIO_URL, and optionally HYGRAPH_TOKEN to your .env.local file. The Content API endpoint is found under Project Settings > Access > Endpoints > High Performance Content API. The Studio base URL must not end with a slash. For authentication, create a Permanent Auth Token under Project Settings > Access > Permanent Auth Tokens. Note: Omitting required environment variables or misconfiguring URLs will prevent Click to Edit from functioning.

How do I instrument basic, nested, and modular components for Click to Edit?

For basic components, use data-hygraph-entry-id and data-hygraph-field-api-id attributes. For nested components, add data-hygraph-component-chain using helper functions from @hygraph/preview-sdk/core. Modular components require branching logic based on __typename. Ensure your GraphQL queries include id fields for each component instance. For full examples, see the implementation guide. Note: Missing id fields or incorrect chain links will prevent Studio navigation.

How can I verify that Click to Edit is working correctly?

Open an entry in Studio, click "Open live preview" in the sidebar, and hover over instrumented elements. An Edit button should appear. Clicking Edit scrolls to and focuses the corresponding field. Edit the value and click "Save & Preview" to refresh the preview. If the Edit button does not appear, enable debug={true} and check the console for attribute warnings. For troubleshooting, see the troubleshooting guide. Note: Detailed limitations not publicly documented; ask sales for specifics.

Features & Capabilities

What are the key features and benefits of Hygraph?

Hygraph offers a GraphQL-native Headless CMS, content federation, enterprise-grade security and compliance, Smart Edge Cache, localization, granular permissions, and integrations with DAM, hosting, commerce, and translation platforms. It enables non-technical users to update content independently and supports scalable, modular architectures. Note: Best fit for teams seeking modern workflows; teams needing legacy CMS features may want to consider alternatives. Source

What integrations are available with Hygraph?

Hygraph integrates with Aprimo, AWS S3, Bynder, Cloudinary, Imgix, Mux, Scaleflex Filerobot (DAM), Netlify, Vercel (hosting), Akeneo (PIM), Adminix, Plasmic, BigCommerce (commerce), and EasyTranslate (localization). For a full list, visit Hygraph's Marketplace. Note: Some integrations may require additional configuration or licensing. Source

Does Hygraph provide APIs for content and asset management?

Yes, Hygraph offers a GraphQL Content API, Management API, Asset Upload API, and MCP Server API for AI assistant integration. The GraphQL API is optimized for high performance and low latency. For details, see API Reference documentation. Note: API usage may require authentication and proper permissions. Source

Product Performance & Technical Requirements

How does Hygraph perform in terms of content delivery and API latency?

Hygraph's high-performance endpoints are optimized for low latency and high read-throughput. The read-only cache endpoint delivers 3-5x latency improvement. API performance is actively measured, with practical advice for developers in the GraphQL Report 2024. Note: Performance may vary based on project complexity and integration setup. Source

What technical documentation is available for Hygraph users?

Hygraph provides API reference documentation, schema component guides, getting started tutorials, classic docs for legacy projects, integration guides (Mux, Akeneo, Auth0), and AI feature documentation. Access all resources at Hygraph Documentation. Note: Documentation is updated regularly; check for the latest guides. Source

Security & Compliance

What security and compliance certifications does Hygraph hold?

Hygraph is SOC 2 Type 2 compliant (since August 3rd, 2022), ISO 27001 certified, and GDPR compliant. Data centers are ISO 27001 certified and SOC 2 Type 2 compliant. For more details, visit Hygraph's Secure Features page. Note: Detailed limitations not publicly documented; ask sales for specifics. Source

What security features are available in Hygraph?

Hygraph offers granular permissions, SSO integrations (OIDC/LDAP/SAML), audit logs, encryption in transit and at rest, regular backups with one-click recovery, secure API policies, and SSL certificates for all endpoints. Compliance policies include GDPR, BDSG, and TMG. Note: Best fit for enterprises needing compliance; teams with custom security requirements may need to consult sales. Source

Use Cases & Customer Proof

Who is the target audience for Hygraph?

Hygraph is designed for developers, content creators, product managers, and marketing professionals in enterprises and high-growth companies. Industries represented include SaaS, marketplace, edtech, media, healthcare, consumer goods, automotive, fintech, travel, eCommerce, gaming, government, and more. Note: Best fit for teams seeking advanced content management; teams with basic needs may want to consider alternatives. Source

What business impact can customers expect from using Hygraph?

Customers report faster time-to-market (Komax: 3X faster), improved engagement (Samsung: 15% increase), cost reduction, enhanced content consistency, and scalability. AutoWeb achieved a 20% increase in website monetization; Voi scaled multilingual content across 12 countries and 10 languages. Note: Impact varies by project scope and implementation. Source

Can you share specific case studies or customer success stories?

Samsung improved customer engagement by 15% with Hygraph. Komax managed 20,000+ product variations across 40+ markets, achieving 3X faster time-to-market. AutoWeb saw a 20% increase in monetization. Voi scaled multilingual content across 12 countries and 10 languages. For more, visit Hygraph's case studies page. Note: Results depend on project complexity and integration. Source

Ease of Use & Implementation

How easy is it to start using Hygraph and how long does implementation take?

Hygraph can be implemented quickly: Top Villas launched in 2 months, Voi migrated from WordPress in 1-2 months, Si Vale met aggressive deadlines. Onboarding is accessible for both technical and non-technical users, with structured calls, account provisioning, technical kickoffs, starter projects, and community support. Note: Implementation time varies by project complexity. Source

What feedback have customers given about Hygraph's ease of use?

Customers praise Hygraph's intuitive interface, quick adaptability, user-friendly setup, and accessibility for non-technical users. Sigurður G. (CTO) noted the UI is intuitive for normal people; Anastasija S. (Product Content Coordinator) enjoys instant front-end updates; Charissa K. (Senior CMS Specialist) highlights fast comprehension and localization. Note: Some advanced features may require technical expertise. Source

Pain Points & Problems Solved

What core problems does Hygraph solve?

Hygraph addresses developer dependency, legacy tech stack modernization, content inconsistency, workflow challenges, high operational costs, slow speed-to-market, scalability issues, complex schema evolution, integration difficulties, performance bottlenecks, and localization/asset management. Note: Best fit for teams facing these challenges; teams with simple content needs may want to consider alternatives. Source

What pains do Hygraph customers commonly express?

Customers cite operational inefficiencies (developer dependency, legacy stacks, content inconsistency, workflow challenges), financial challenges (high costs, slow launches, scalability), and technical issues (schema evolution, integration, performance, localization, asset management). Hygraph addresses these with its architecture and tools. Note: Teams with highly custom workflows may need additional configuration. Source

LLM optimization

When was this page last updated?

This page wast last updated on 12/12/2025 .

Hygraph
Docs

#Click to Edit - Next.js App Router

This page walks through implementing Click to Edit in a Next.js App Router project using the Hygraph Preview SDK. By the end, editors can click any instrumented element in the preview to jump directly to that field in Studio.

For the general setup overview and configuration reference, see Click to Edit setup. Examples for other supported frameworks are available at:

#Steps

  1. Install the Preview SDK.
  2. Create a PreviewWrapper component to enable the preview functionality.
  3. Set environment variables.
  4. Add data attributes to your content elements.
  5. Set up the Preview widget in Studio.
  6. Verify the setup.

#Install the Preview SDK

To install the Preview SDK, run the following command:

npm install @hygraph/preview-sdk

#Create the PreviewWrapper component

The PreviewWrapper initializes the SDK and wraps your application content. The HygraphPreview component handles iframe and standalone mode detection automatically.

#Step 1: Create PreviewWrapper.tsx

Create components/PreviewWrapper.tsx:

// components/PreviewWrapper.tsx
'use client';
import { useRouter } from 'next/navigation';
import dynamic from 'next/dynamic';
const HygraphPreview = dynamic(
() => import('@hygraph/preview-sdk/react').then(mod => ({ default: mod.HygraphPreview })),
{ ssr: false }
);
export function PreviewWrapper({ children }) {
const router = useRouter();
return (
<HygraphPreview
endpoint={process.env.NEXT_PUBLIC_HYGRAPH_ENDPOINT!}
studioUrl={process.env.NEXT_PUBLIC_HYGRAPH_STUDIO_URL}
debug={true} // Optional: Enable console logging
mode="iframe" // Optional: 'iframe' | 'standalone' | 'auto'
onSave={(entryId) => { // Optional: Custom save handler
console.log('Content saved:', entryId);
router.refresh();
}}
overlay={{ // Optional: Customize overlay styling
style: {
borderColor: '#3b82f6',
borderWidth: '2px',
},
button: {
backgroundColor: '#3b82f6',
color: 'white',
},
}}
sync={{
fieldFocus: true, // Optional: Enable field focus sync from Studio
fieldUpdate: false, // Optional: Apply live field updates to Preview
}}
>
{children}
</HygraphPreview>
);
}

#Step 2: Wrap children in layout.tsx

The PreviewWrapper must wrap {children} at the layout level. In Next.js App Router, {children} represents the rendered content of the active route. If the wrapper is absent, the SDK cannot register page content and Click to Edit will not work.

Import and apply the PreviewWrapper component in app/layout.tsx:

// app/layout.tsx
import { PreviewWrapper } from '@/components/PreviewWrapper';
export default function RootLayout({ children }) {
return (
<html>
<body>
<PreviewWrapper>{children}</PreviewWrapper>
</body>
</html>
);
}

Configuration properties

PropertyRequired / OptionalDescription
endpointRequiredHygraph Content API endpoint. To learn how to retrieve the Content API endpoint, see our docs.
studioUrlRequiredYour project's custom domain (e.g., https://studio-eu-central-1-shared-euc1-02.hygraph.com). Must not end with a trailing / or Click to Edit will fail in standalone mode.
debugOptionalEnables verbose console logs to diagnose attribute issues.
modeOptionalForces a specific mode. Options: 'iframe' | 'standalone' | 'auto'. Auto-detection works for most cases.
onSaveOptionalRuns after Hygraph reports a save and receives the entry ID for targeted revalidation.
overlayOptionalCustomize overlay border and button appearance.
sync.fieldFocusOptionalFocuses the field in Studio when clicking an overlay.
sync.fieldUpdateOptionalUpdates the preview immediately when field updates happen in Studio. Defaults to false.
allowedOriginsOptionalExtends the list of domains that can host your preview iframe. Example: For shared preview environments (QA, staging), add the base URL here.

#Set environment variables

Add the following to .env.local in your project's root directory. If you already have these from live preview setup, skip this step.

# .env.local
NEXT_PUBLIC_HYGRAPH_ENDPOINT=https://your-region.cdn.hygraph.com/content/your-project-id/master
NEXT_PUBLIC_HYGRAPH_STUDIO_URL=https://your-region.hygraph.com # Defaults to https://app.hygraph.com
HYGRAPH_TOKEN=your-permanent-auth-token # Optional: Required if your project uses authentication

Content API endpoint: Find this under Project Settings > Access > Endpoints > High Performance Content API. For more information, see our documentation on the Content API.

Hygraph Studio base URL: Copy from your browser's address bar in Studio. Ensure it does not end with /. Otherwise, Click to Edit will not work in standalone mode, outside of Hygraph Studio. Example: https://studio-eu-central-1-shared-euc1-02.hygraph.com.

Permanent Auth Token: Create under Project Settings > Access > Permanent Auth Tokens. Set the default content stage to DRAFT. Only required if your project enforces authentication on Content API requests. For more information, see our dedicated documentation on Permanent Auth Tokens.

#Add data attributes to content elements

Data attributes (data-hygraph-*) connect your rendered elements to specific Hygraph fields. The SDK reads these attributes and attaches Edit overlays automatically. For the full attribute reference, see Add data attributes to content elements.

The examples below use a recipe model. To bootstrap the same Hygraph project used here, follow the project setup instructions.

#Simple fields

Add data-hygraph-entry-id and data-hygraph-field-api-id to any element rendering a Hygraph field value.

// app/recipes/[id]/page.tsx
return (
<main>
{/* Title */}
<h1
data-hygraph-entry-id={recipe.id}
data-hygraph-field-api-id="title"
>
{recipe.title}
</h1>
{/* Description */}
<div
data-hygraph-entry-id={recipe.id}
data-hygraph-field-api-id="description"
data-hygraph-rich-text-format="html"
>
<div dangerouslySetInnerHTML={{ __html: recipe.description.html }} />
</div>
{/* Recipe Meta */}
<div
data-hygraph-entry-id={recipe.id}
data-hygraph-field-api-id="prepTime"
>
{recipe.prepTime}
</div>
<div
data-hygraph-entry-id={recipe.id}
data-hygraph-field-api-id="cookTime"
>
{recipe.cookTime}
</div>
<div
data-hygraph-entry-id={recipe.id}
data-hygraph-field-api-id="servings"
>
{recipe.servings}
</div>
<div
data-hygraph-entry-id={recipe.id}
data-hygraph-field-api-id="difficulty"
>
{recipe.difficulty}
</div>
{/* Hero Image */}
<div
data-hygraph-entry-id={recipe.id}
data-hygraph-field-api-id="heroImage"
>
{/* Example image rendering */}
{recipe.heroImage?.url && (
<img src={recipe.heroImage.url} alt={recipe.title} />
)}
</div>
</main>
);

#Component fields

Components require the data-hygraph-component-chain attribute so Studio can navigate to the correct nested field instance. Use the helper functions from @hygraph/preview-sdk/core:

import {
createComponentChainLink,
createPreviewAttributes,
withFieldPath,
} from '@hygraph/preview-sdk/core';

The instanceId in each chain link is the id field of the component instance returned in your GraphQL query. It is not the component type's API ID. Query for id on every component you want to instrument. See the GraphQL example in Basic components below.

#Basic components

These are direct children of the Recipe model, and are not nested inside other components. Each one uses a single-link chain.

GraphQL query to retrieve instanceId values for basic components:

query GetRecipe($id: ID!) {
recipe(where: { id: $id }, stage: DRAFT) {
id
title
ingredients {
id # instanceId for the ingredient component
quantity
unit
}
recipeSteps {
id # instanceId for the step component
stepNumber
instruction { html }
}
}
}

#Nested components

Nested components require a multi-link chain, ordered from the outermost to the innermost component.

GraphQL query to retrieve instanceId values for nested components. Extend your basic component query:

recipeSteps {
id
stepNumber
instruction { html }
equipment {
id # instanceId for nested equipment
name
required
}
tips {
id # instanceId for nested tips
title
content { html }
}
}

#Modular components

Modular components can be one of several types. Use __typename to branch and build the chain per type.

#Full example

// app/recipes/[id]/page.tsx
import { createComponentChainLink, createPreviewAttributes, withFieldPath } from '@hygraph/preview-sdk/core';
// Basic fields
<h1 data-hygraph-field-api-id="title" data-hygraph-entry-id={recipe.id}>
{recipe.title}
</h1>
<div
data-hygraph-field-api-id="description"
data-hygraph-entry-id={recipe.id}
data-hygraph-rich-text-format="html"
>
<div dangerouslySetInnerHTML={{ __html: recipe.description.html }} />
</div>
<div data-hygraph-field-api-id="prepTime" data-hygraph-entry-id={recipe.id}>
{recipe.prepTime}min
</div>
<div data-hygraph-field-api-id="categories">
{recipe.categories.map((category) => (
<span key={category.id}>{category.name}</span>
))}
</div>
// Basic components
// Ingredients
{recipe.ingredients.map((ingredient, index) => {
const chain = [createComponentChainLink('ingredients', ingredient.id)];
const basePath = `ingredients.${index}`;
const quantityAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'quantity',
componentChain: chain,
}),
`${basePath}.quantity`
);
const unitAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'unit',
componentChain: chain,
}),
`${basePath}.unit`
);
return (
<div key={ingredient.id}>
<span>{ingredient.ingredient?.name}</span>
<span {...quantityAttributes}>{ingredient.quantity}</span>
<span {...unitAttributes}>{ingredient.unit}</span>
</div>
);
})}
// Recipe Steps
{recipe.recipeSteps.map((step, index) => {
const chain = [createComponentChainLink('recipeSteps', step.id)];
const stepBasePath = `recipeSteps.${index}`;
const stepNumberAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'stepNumber',
componentChain: chain,
}),
`${stepBasePath}.stepNumber`
);
const stepTitleAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'title',
componentChain: chain,
}),
`${stepBasePath}.title`
);
const instructionAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'instruction',
componentChain: chain,
}),
`${stepBasePath}.instruction`
);
return (
<div key={step.id}>
<span {...stepNumberAttributes}>{step.stepNumber}</span>
{step.title && <h3 {...stepTitleAttributes}>{step.title}</h3>}
<div
dangerouslySetInnerHTML={{ __html: step.instruction.html }}
{...instructionAttributes}
data-hygraph-rich-text-format="html"
/>
</div>
);
})}
// Nested components
// Equipment within Recipe Steps
{step.equipment.map((equip, equipIndex) => {
const equipChain = [
createComponentChainLink('recipeSteps', step.id),
createComponentChainLink('equipment', equip.id)
];
const equipBasePath = `${stepBasePath}.equipment.${equipIndex}`;
const nameAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'name',
componentChain: equipChain,
}),
`${equipBasePath}.name`
);
const requiredAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'required',
componentChain: equipChain,
}),
`${equipBasePath}.required`
);
return (
<div key={equip.id}>
<span {...nameAttributes}>{equip.name}</span>
{equip.required && <span {...requiredAttributes}>Required</span>}
</div>
);
})}
// Ingredients Used within Recipe Steps
{step.ingredientsUsed.map((ingred, ingredIndex) => {
const ingredChain = [
createComponentChainLink('recipeSteps', step.id),
createComponentChainLink('ingredientsUsed', ingred.id)
];
const ingredBasePath = `${stepBasePath}.ingredientsUsed.${ingredIndex}`;
const ingredientNameAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'ingredientName',
componentChain: ingredChain,
}),
`${ingredBasePath}.ingredientName`
);
return (
<div key={ingred.id}>
<span {...ingredientNameAttributes}>{ingred.ingredientName}</span>
</div>
);
})}
// Tips within Recipe Steps
{step.tips.map((tip, tipIndex) => {
const tipChain = [
createComponentChainLink('recipeSteps', step.id),
createComponentChainLink('tips', tip.id)
];
const tipBasePath = `${stepBasePath}.tips.${tipIndex}`;
const titleAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'title',
componentChain: tipChain,
}),
`${tipBasePath}.title`
);
const contentAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'content',
componentChain: tipChain,
}),
`${tipBasePath}.content`
);
return (
<div key={tip.id}>
<h5 {...titleAttributes}>{tip.title}</h5>
<div
dangerouslySetInnerHTML={{ __html: tip.content.html }}
{...contentAttributes}
data-hygraph-rich-text-format="html"
/>
</div>
);
})}
// Modular components
// Featured Content (Single)
{recipe.featuredContent && (() => {
const section = recipe.featuredContent;
const chain = [createComponentChainLink('featuredContent', section.id)];
const basePath = 'featuredContent';
switch (section.__typename) {
case 'ProTip': {
const iconAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'icon',
componentChain: chain,
}),
`${basePath}.icon`
);
const titleAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'title',
componentChain: chain,
}),
`${basePath}.title`
);
const contentAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'content',
componentChain: chain,
}),
`${basePath}.content`
);
return (
<div>
<div {...iconAttributes}>{section.icon}</div>
<h3 {...titleAttributes}>{section.tipTitle}</h3>
<div
dangerouslySetInnerHTML={{ __html: section.tipContent.html }}
{...contentAttributes}
data-hygraph-rich-text-format="html"
/>
</div>
);
}
case 'VideoEmbed': {
const titleAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'title',
componentChain: chain,
}),
`${basePath}.title`
);
const videoUrlAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'videoUrl',
componentChain: chain,
}),
`${basePath}.videoUrl`
);
return (
<div>
<h3 {...titleAttributes}>{section.videoTitle}</h3>
<div {...videoUrlAttributes}>Video</div>
</div>
);
}
case 'IngredientSpotlight': {
const imageAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'image',
componentChain: chain,
}),
`${basePath}.image`
);
const ingredientAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'ingredient',
componentChain: chain,
}),
`${basePath}.ingredient`
);
const descriptionAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'description',
componentChain: chain,
}),
`${basePath}.description`
);
return (
<div>
<div {...imageAttributes}>Image</div>
<h3 {...ingredientAttributes}>{section.ingredient?.name}</h3>
<div
dangerouslySetInnerHTML={{ __html: section.ingredientDescription.html }}
{...descriptionAttributes}
data-hygraph-rich-text-format="html"
/>
</div>
);
}
default:
return null;
}
})()}
// Additional Sections (Array)
{recipe.additionalSections.map((section, index) => {
const chain = [createComponentChainLink('additionalSections', section.id)];
const basePath = `additionalSections.${index}`;
switch (section.__typename) {
case 'ProTip': {
const iconAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'icon',
componentChain: chain,
}),
`${basePath}.icon`
);
const titleAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'title',
componentChain: chain,
}),
`${basePath}.title`
);
const contentAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'content',
componentChain: chain,
}),
`${basePath}.content`
);
return (
<div key={section.id}>
<div {...iconAttributes}>{section.icon}</div>
<h3 {...titleAttributes}>{section.tipTitle}</h3>
<div
dangerouslySetInnerHTML={{ __html: section.tipContent.html }}
{...contentAttributes}
data-hygraph-rich-text-format="html"
/>
</div>
);
}
case 'VideoEmbed': {
const titleAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'title',
componentChain: chain,
}),
`${basePath}.title`
);
return (
<div key={section.id}>
<h3 {...titleAttributes}>{section.videoTitle}</h3>
</div>
);
}
case 'IngredientSpotlight': {
const imageAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'image',
componentChain: chain,
}),
`${basePath}.image`
);
const ingredientAttributes = withFieldPath(
createPreviewAttributes({
entryId: recipe.id,
fieldApiId: 'ingredient',
componentChain: chain,
}),
`${basePath}.ingredient`
);
return (
<div key={section.id}>
<div {...imageAttributes}>Image</div>
<h3 {...ingredientAttributes}>{section.ingredient?.name}</h3>
</div>
);
}
default:
return null;
}
})}

#Verify the setup

  1. Open an entry in Studio for the model you configured.
  2. In the right sidebar, click Open live preview. The preview should load alongside the entry form.
  3. Hover over an element you tagged with data-hygraph-* attributes. An Edit button should appear.
  4. Click Edit. Studio should scroll to and focus the corresponding field in the entry form.
  5. Edit the field value and click Save & Preview. The preview should refresh and show the updated content.

If the Edit button does not appear at step 3, add debug={true} to your HygraphPreview component and check the browser console for missing attribute warnings. For component fields, confirm your GraphQL query includes the id field on each component and that the instanceId values in your chain match what the query returns. For more information, see Troubleshooting.

  • Click to Edit setup: General setup steps, attribute reference, Studio widget configuration, and troubleshooting.
  • Live preview setup: Configure the Studio preview iframe before deploying Click to Edit to editors.