`** becomes clickable (opens URL A).
- **`page.footnote`**: walks up from `
`, hits the boundary → traversal stops, the **`
`** itself becomes clickable (opens URL B). The outer group is not reached.
**Example 4: Multiple stega strings without groups (collision warning)**
```tsx
{/* Both product.name and product.tagline contain stega encoding */}
{product.name}
{product.tagline}
```
Both stega-encoded strings resolve to the same `
` element. The library logs a console warning and the last URL wins. To fix this, wrap each piece of content in its own element:
```tsx
{product.name}
{product.tagline}
```
## Structured Text fields
Structured Text fields require special attention because of how stega encoding works within them:
- The DatoCMS API encodes stega information inside a single `
` within the structured text output. Without any configuration, only that small span would be clickable.
- Structured Text fields can contain **embedded blocks** and **inline records**, each with their own editing URL that should open a different record in the editor.
Here are the rules to follow:
### Rule 1: Always wrap the Structured Text component in a group
This makes the entire structured text area clickable, instead of just the tiny stega-encoded span:
```tsx
```
### Rule 2: Wrap embedded blocks, inline records, and inline blocks in a boundary
Embedded blocks, inline records, and inline blocks have their own edit URL (pointing to the block/record). Without a boundary, clicking them would bubble up to the parent group and open the structured text field editor instead. Add `data-datocms-content-link-boundary` to prevent them from merging into the parent group:
```tsx
(
)}
renderInlineRecord={({ record }) => (
)}
renderLinkToRecord={({ record, children, transformedMeta }) => (
{children}
)}
renderInlineBlock={({ record }) => (
)}
/>
```
With this setup:
- Clicking the main text (paragraphs, headings, lists) opens the **structured text field editor**
- Clicking an embedded block, inline record, or inline block opens **that record's editor**
**Why `renderLinkToRecord` doesn't need a boundary:** Record links are typicall just `` tags wrapping text that already belongs to the surrounding structured text. Since they don't introduce a separate editing target, there's no URL collision and no reason to isolate them from the parent group.
## Low-level utilities
The `react-datocms` package re-exports utility functions from `@datocms/content-link` for working with stega-encoded content:
### `decodeStega`
Decodes stega-encoded content to extract editing metadata:
```typescript
import { decodeStega } from 'react-datocms';
const text = "Hello, world!"; // Contains invisible stega data
const decoded = decodeStega(text);
if (decoded) {
console.log('Editing URL:', decoded.url);
console.log('Clean text:', decoded.cleanText);
}
```
### `stripStega`
Removes stega encoding from any data type (strings, objects, arrays, primitives):
```typescript
import { stripStega } from 'react-datocms';
// Works with strings
stripStega("HelloWorld") // "HelloWorld"
// Works with objects
stripStega({ name: "John", age: 30 })
// Works with nested structures - removes ALL stega encodings
stripStega({
users: [
{ name: "Alice", email: "alice.com" },
{ name: "Bob", email: "bob.co" }
]
})
// Works with arrays
stripStega(["First", "Second", "Third"])
```
These utilities are useful when you need to:
- Extract clean text for meta tags or social sharing
- Check if content has stega encoding
- Debug Visual Editing issues
- Process stega-encoded content programmatically
## Troubleshooting
### Click-to-edit overlays not appearing
**Problem**: Overlays don't appear when clicking on content.
**Solutions**:
1. Verify stega encoding is enabled in your API calls:
```js
const result = await executeQuery(query, {
token: 'YOUR_API_TOKEN',
contentLink: 'v1',
baseEditingUrl: 'https://your-project.admin.datocms.com',
});
```
2. Check that `` is mounted in your component tree
3. Ensure you've enabled click-to-edit mode:
```jsx
```
Or hold Alt/Option key while browsing
4. Check browser console for errors
### Navigation not syncing with [Web Previews plugin](https://www.datocms.com/marketplace/plugins/i/datocms-plugin-web-previews)
**Problem**: When you navigate in your preview, the DatoCMS editor doesn't follow along.
**Solutions**:
1. Ensure you're providing both `onNavigateTo` and `currentPath` props:
```jsx
router.push(path)}
currentPath={pathname}
/>
```
2. Verify `currentPath` updates when navigation occurs
3. Check that `baseEditingUrl` in your API calls matches your preview URL
### StructuredText blocks not clickable
**Problem**: Content within StructuredText blocks doesn't have click-to-edit overlays.
**Solutions**:
1. Wrap StructuredText with `data-datocms-content-link-group` (see [Rule 1](#rule-1-always-wrap-the-structured-text-component-in-a-group)):
```jsx
```
2. Add `data-datocms-content-link-boundary` to custom blocks and inline blocks (see [Rule 2](#rule-2-wrap-embedded-blocks-and-inline-records-in-a-boundary)):
```jsx
renderBlock={({ record }) => (
)}
renderInlineBlock={({ record }) => (
)}
```
### Layout issues caused by stega encoding
**Problem**: The invisible zero-width characters can cause unexpected letter-spacing or text breaking out of containers.
**Solutions**:
1. Use the `stripStega` prop to remove stega encoding after processing:
```jsx
```
2. Or use CSS to fix the letter-spacing issue:
```css
[data-datocms-contains-stega] {
letter-spacing: 0 !important;
}
```
This attribute is automatically added to elements with stega-encoded content when `stripStega` is `false` (the default).