`** 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)**
```html
{{ 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:
```html
{{ 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:
```vue
```
### 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.
**Why `renderLinkToRecord` doesn't need a boundary:** Record links are typically 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 with the parent group and no reason to isolate them with a boundary. Clicking a record link simply opens the structured text field editor — the same behavior you'd get clicking any other text in the paragraph — which is the correct outcome since the link text is part of the structured text content itself.
```vue
{{ data.blogPost.title }}
```
With this setup:
- Clicking the main text (paragraphs, headings, lists, and record links) opens the **structured text field editor**
- Clicking an embedded block, inline record, or inline block opens **that record's editor**
## Low-level utilities
The `vue-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 'vue-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 by converting to JSON, removing all stega-encoded segments, and parsing back to the original type:
```typescript
import { stripStega } from 'vue-datocms';
// Works with strings
stripStega("Hello\u200EWorld") // "HelloWorld"
// Works with objects
stripStega({ name: "John\u200E", age: 30 })
// Works with nested structures - removes ALL stega encodings
stripStega({
users: [
{ name: "Alice\u200E", email: "alice\u200E.com" },
{ name: "Bob\u200E", email: "bob\u200E.co" }
]
})
// Works with arrays
stripStega(["First\u200E", "Second\u200E", "Third\u200E"])
```
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
1. **Check client configuration**: Make sure you've configured your DatoCMS client with `contentLink: 'v1'` and `baseEditingUrl`
2. **Verify content is stega-encoded**: Use `decodeStega()` on a text field to check if metadata is present
3. **Enable click-to-edit**: Either press Alt/Option key or set `enable-click-to-edit` prop to `true` (e.g., `:enable-click-to-edit="true"`)
4. **Check console for errors**: Look for any JavaScript errors that might prevent the controller from initializing
### Overlays appearing in wrong places
1. **Layout shifts**: If your page layout shifts after content loads, overlays may be positioned incorrectly. Try triggering a window resize event after content loads
2. **Transformed elements**: CSS transforms on parent elements can affect overlay positioning
### Navigation not working in Web Previews plugin
1. **Check `onNavigateTo` callback**: Make sure you're passing a valid navigation function
2. **Verify `currentPath` prop**: Ensure you're passing the current route path
3. **Test router integration**: Verify that your router navigation works outside of Visual Editing
### Performance issues with many editable elements
1. **Use `root` prop**: Limit scanning to a specific container instead of the entire document
2. **Avoid enabling on mount**: Use Alt/Option key activation instead of passing options to `enable-click-to-edit` prop
3. **Debounce updates**: If you're frequently updating `currentPath`, consider debouncing the updates
### Content not clickable inside StructuredText
1. **Add edit group**: Wrap StructuredText with `data-datocms-content-link-group`
2. **Check boundaries**: Make sure you're not inadvertently blocking clicks with `data-datocms-content-link-boundary` on parent elements
3. **Verify stega encoding**: Check that your GraphQL query includes text fields with stega encoding enabled
### Layout issues caused by stega encoding
The invisible zero-width characters can cause unexpected letter-spacing or text breaking out of containers. To fix this, either use `stripStega: true`, or use CSS: `[data-datocms-contains-stega] { letter-spacing: 0 !important; }`. This attribute is automatically added to elements with stega-encoded content when `stripStega: false` (the default).