`** 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)**
```svelte
{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:
```svelte
{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:
```svelte
```
### Rule 2: Wrap embedded blocks, inline blocks, and inline records in a boundary
Embedded blocks, inline blocks, and inline records each 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 the root element of your custom components to prevent them from merging into the parent group.
**Note on record links (item links):** Record links (`isItemLink`) typically do **not** need a boundary. They render as `` tags wrapping text that already belongs to the surrounding structured text. Unlike embedded blocks or inline records, record links don't introduce a separate editing target with its own stega-encoded URL, so there's no URL collision and no reason to isolate them from the parent group. When an editor clicks on that text, it correctly opens the structured text field editor (the parent group). Only add a boundary to a record link if you specifically want clicking it to open the linked record's editor instead.
```svelte
```
Then, in your custom components, wrap the root element with `data-datocms-content-link-boundary`:
```svelte
{block.title}
{block.description}
```
```svelte
{block.username}
```
```svelte
{link.title}
```
Record links don't need a boundary — their content belongs to the surrounding structured text:
```svelte
```
With this setup:
- Clicking the main text (paragraphs, headings, lists) — including record links — opens the **structured text field editor**
- Clicking an embedded block, inline block, or inline record opens **that record's editor**
## Low-level utilities
The `@datocms/svelte` 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 '@datocms/svelte';
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:
```typescript
import { stripStega } from '@datocms/svelte';
// 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:
```svelte
```
Or hold Alt/Option key while browsing
4. Check browser console for errors
### Navigation not syncing with Web Previews plugin
**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:
```svelte
goto(path)}
currentPath={$page.url.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`:
```svelte
```
2. Add `data-datocms-content-link-boundary` to custom blocks, inline blocks, and inline records to prevent them from bubbling to the parent field (record links typically don't need a boundary)
### 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:
```svelte
```
2. Use CSS to reset letter-spacing on elements with stega-encoded content:
```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)