# Visual Editing with click-to-edit overlays
`` enables Visual Editing for your DatoCMS content by providing click-to-edit overlays. It's built on top of the framework-agnostic [`@datocms/content-link`](https://www.npmjs.com/package/@datocms/content-link) library.
## What is Visual Editing?
Visual Editing transforms how editors interact with your content by letting them see and edit it directly in the context of your website. Instead of switching between the CMS and the live site, editors can:
- **See content in context**: View draft content exactly as it appears on the website
- **Click to edit**: Click any content element to instantly open the editor for that specific field
- **Navigate seamlessly**: Browse between pages while staying in editing mode
- **Get instant feedback**: See changes immediately without page refreshes
## Out-of-the-box features
- **Click-to-edit overlays**: Visual indicators showing which content is editable
- **Stega decoding**: Automatically detects stega-encoded metadata from DatoCMS GraphQL responses
- **Keyboard shortcuts**: Hold Alt/Option key to temporarily toggle click-to-edit mode
- **Flash-all highlighting**: Animated effect to show all editable elements at once
- **Bidirectional navigation**: Sync URL changes between your preview and the DatoCMS interface
- **Framework-agnostic**: Works with any Astro setup (with or without View Transitions)
- **StructuredText integration**: Special handling for complex structured content fields
- **Web Previews plugin integration**: Automatic bidirectional communication when running inside the DatoCMS Web Previews plugin
- [Installation](#installation)
- [Basic Setup](#basic-setup)
- [Step 1: Fetch content with Content Link metadata](#step-1-fetch-content-with-content-link-metadata)
- [Step 2: Add the ContentLink component](#step-2-add-the-contentlink-component)
- [Usage](#usage)
- [Props](#props)
- [`enableClickToEdit` options](#enableclicktoedit-options)
- [Data attributes reference](#data-attributes-reference)
- [Developer-specified attributes](#developer-specified-attributes)
- [`data-datocms-content-link-url`](#data-datocms-content-link-url)
- [`data-datocms-content-link-source`](#data-datocms-content-link-source)
- [`data-datocms-content-link-group`](#data-datocms-content-link-group)
- [`data-datocms-content-link-boundary`](#data-datocms-content-link-boundary)
- [Library-managed attributes](#library-managed-attributes)
- [`data-datocms-contains-stega`](#data-datocms-contains-stega)
- [`data-datocms-auto-content-link-url`](#data-datocms-auto-content-link-url)
- [How group and boundary resolution works](#how-group-and-boundary-resolution-works)
- [Structured Text fields](#structured-text-fields)
- [Rule 1: Always wrap the Structured Text component in a group](#rule-1-always-wrap-the-structured-text-component-in-a-group)
- [Rule 2: Wrap embedded blocks, inline blocks, and inline records in a boundary](#rule-2-wrap-embedded-blocks-inline-blocks-and-inline-records-in-a-boundary)
- [Low-level utilities](#low-level-utilities)
- [`stripStega()` works with any data type](#stripstega-works-with-any-data-type)
- [Troubleshooting](#troubleshooting)
- [Click-to-edit overlays not appearing](#click-to-edit-overlays-not-appearing)
- [Navigation not syncing in Web Previews plugin](#navigation-not-syncing-in-web-previews-plugin)
- [Content inside StructuredText not clickable](#content-inside-structuredtext-not-clickable)
- [Layout issues caused by stega encoding](#layout-issues-caused-by-stega-encoding)
## Installation
```bash
npm install --save @datocms/astro
```
Note that `@datocms/content-link` is included as a dependency and will be installed automatically.
## Basic Setup
### Step 1: Fetch content with Content Link metadata
Make sure you pass the `contentLink` and `baseEditingUrl` options when fetching content from DatoCMS:
```astro
---
import { executeQuery } from '@datocms/cda-client';
const query = `
query {
blogPost {
title
content
}
}
`;
const result = await executeQuery(query, {
token: import.meta.env.DATOCMS_API_TOKEN,
contentLink: 'v1',
baseEditingUrl: 'https://your-project.admin.datocms.com',
});
---
```
The `contentLink: 'v1'` option enables stega encoding, which embeds invisible metadata into text fields. The `baseEditingUrl` tells DatoCMS where your project is located so edit URLs can be generated correctly. Both options are required.
### Step 2: Add the ContentLink component
Add the `` component to your page or layout. This component renders nothing visible but activates all the Visual Editing features:
```astro
---
import { ContentLink } from '@datocms/astro/ContentLink';
---
```
That's it! The component will automatically:
- Scan the page for stega-encoded content
- Enable Alt/Option key toggling for click-to-edit mode
- Connect to the Web Previews plugin if running inside its iframe
- Handle navigation synchronization
## Usage
The ContentLink component works seamlessly whether or not your Astro site uses [View Transitions](https://docs.astro.build/en/guides/view-transitions/). Simply add it to your layout:
```astro
---
// src/layouts/Layout.astro
import { ContentLink } from '@datocms/astro/ContentLink';
---
```
The component automatically handles both scenarios:
- **With View Transitions**: Listens to `astro:page-load` events and syncs the URL with the Web Previews plugin during client-side navigation
- **Without View Transitions**: Still initializes correctly and handles navigation via standard page reloads
You get the full Visual Editing experience regardless of your routing setup.
## Props
| Prop | Type | Default | Description |
| ------------------- | --------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `enableClickToEdit` | `boolean \| { scrollToNearestTarget?: boolean; hoverOnly?: boolean }` | - | Enable click-to-edit overlays on mount. Use `true` for immediate activation, or pass options object (see below) |
| `stripStega` | `boolean` | `false` | Strip stega-encoded invisible characters from text content. When `true`, encoding is permanently removed (prevents controller recreation) |
### `enableClickToEdit` options
When passing an options object to `enableClickToEdit`, the following properties are available:
| Option | Type | Default | Description |
| ----------------------- | --------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `scrollToNearestTarget` | `boolean` | `false` | Automatically scroll to the nearest editable element if none is currently visible in the viewport when click-to-edit mode is enabled |
| `hoverOnly` | `boolean` | `false` | Only enable click-to-edit on devices that support hover (non-touch). Uses `window.matchMedia('(hover: hover)')` to detect hover capability. On touch devices, users can still toggle with Alt/Option |
**Examples:**
```astro
```
The `hoverOnly` option is particularly useful for websites that receive traffic from both desktop and mobile users. On touch devices, the click-to-edit overlays can interfere with normal scrolling and tapping behavior. By setting `hoverOnly: true`, overlays will only appear automatically on devices with a mouse or trackpad, while touch device users can still access click-to-edit mode by pressing and holding the Alt/Option key.
## Data attributes reference
This library uses several `data-datocms-*` attributes. Some are **developer-specified** (you add them to your markup), and some are **library-managed** (added automatically during DOM stamping). Here's a complete reference.
### Developer-specified attributes
These attributes are added by you in your templates/components to control how editable regions behave.
#### `data-datocms-content-link-url`
Manually marks an element as editable with an explicit edit URL. Use this for non-text fields (booleans, numbers, dates, JSON) that cannot contain stega encoding. The recommended approach is to use the `_editingUrl` field available on all records:
```graphql
query {
product {
id
price
isActive
_editingUrl
}
}
```
```astro
${product.price}
```
#### `data-datocms-content-link-source`
Attaches stega-encoded metadata without the need to render it as content. Useful for structural elements that cannot contain text (like `