@dotcms/vue 1.5.5-next.2350

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +719 -0
  2. package/index.d.ts +16 -0
  3. package/index.js +912 -0
  4. package/lib/__test__/mocks.d.ts +6 -0
  5. package/lib/client/dotcms-client.plugin.d.ts +79 -0
  6. package/lib/components/Column/Column.vue.d.ts +12 -0
  7. package/lib/components/Container/Container.vue.d.ts +11 -0
  8. package/lib/components/Container/ContainerNotFound.vue.d.ts +6 -0
  9. package/lib/components/Container/EmptyContainer.vue.d.ts +2 -0
  10. package/lib/components/Contentlet/Contentlet.vue.d.ts +14 -0
  11. package/lib/components/Contentlet/constants.d.ts +2 -0
  12. package/lib/components/DotCMSBlockEditorRenderer/DotCMSBlockEditorRenderer.vue.d.ts +5 -0
  13. package/lib/components/DotCMSBlockEditorRenderer/components/BlockEditorBlock.vue.d.ts +13 -0
  14. package/lib/components/DotCMSBlockEditorRenderer/components/blocks/BulletList.vue.d.ts +17 -0
  15. package/lib/components/DotCMSBlockEditorRenderer/components/blocks/CodeBlock.vue.d.ts +22 -0
  16. package/lib/components/DotCMSBlockEditorRenderer/components/blocks/DotContent.vue.d.ts +10 -0
  17. package/lib/components/DotCMSBlockEditorRenderer/components/blocks/DotImage.vue.d.ts +7 -0
  18. package/lib/components/DotCMSBlockEditorRenderer/components/blocks/DotVideo.vue.d.ts +7 -0
  19. package/lib/components/DotCMSBlockEditorRenderer/components/blocks/GridBlock.vue.d.ts +10 -0
  20. package/lib/components/DotCMSBlockEditorRenderer/components/blocks/Heading.vue.d.ts +22 -0
  21. package/lib/components/DotCMSBlockEditorRenderer/components/blocks/ListItem.vue.d.ts +17 -0
  22. package/lib/components/DotCMSBlockEditorRenderer/components/blocks/NoComponentProvided.vue.d.ts +6 -0
  23. package/lib/components/DotCMSBlockEditorRenderer/components/blocks/OrderedList.vue.d.ts +17 -0
  24. package/lib/components/DotCMSBlockEditorRenderer/components/blocks/Paragraph.vue.d.ts +22 -0
  25. package/lib/components/DotCMSBlockEditorRenderer/components/blocks/Quote.vue.d.ts +17 -0
  26. package/lib/components/DotCMSBlockEditorRenderer/components/blocks/TableRenderer.vue.d.ts +15 -0
  27. package/lib/components/DotCMSBlockEditorRenderer/components/blocks/TextBlock.vue.d.ts +13 -0
  28. package/lib/components/DotCMSBlockEditorRenderer/components/blocks/UnknownBlock.vue.d.ts +10 -0
  29. package/lib/components/DotCMSBlockEditorRenderer/types.d.ts +44 -0
  30. package/lib/components/DotCMSEditableText/DotCMSEditableText.vue.d.ts +15 -0
  31. package/lib/components/DotCMSEditableText/utils.d.ts +22 -0
  32. package/lib/components/DotCMSLayoutBody/DotCMSLayoutBody.vue.d.ts +5 -0
  33. package/lib/components/DotCMSLayoutBody/components/ErrorMessage.vue.d.ts +2 -0
  34. package/lib/components/DotCMSLayoutBody/types.d.ts +25 -0
  35. package/lib/components/DotCMSShow/DotCMSShow.vue.d.ts +35 -0
  36. package/lib/components/FallbackComponent/FallbackComponent.vue.d.ts +13 -0
  37. package/lib/components/Row/Row.vue.d.ts +13 -0
  38. package/lib/composables/useCheckVisibleContent.d.ts +16 -0
  39. package/lib/composables/useDotCMSShowWhen.d.ts +20 -0
  40. package/lib/composables/useEditableDotCMSPage.d.ts +37 -0
  41. package/lib/composables/useIsAnalyticsActive.d.ts +14 -0
  42. package/lib/composables/useIsDevMode.d.ts +23 -0
  43. package/lib/contexts/dotcms-page.context.d.ts +74 -0
  44. package/lib/utils/imageLoader.d.ts +54 -0
  45. package/lib/utils/toPlain.d.ts +12 -0
  46. package/package.json +47 -0
  47. package/test-setup.d.ts +0 -0
package/README.md ADDED
@@ -0,0 +1,719 @@
1
+ # dotCMS Vue SDK
2
+
3
+ The `@dotcms/vue` SDK is the dotCMS official Vue 3 library. It empowers Vue developers to build powerful, editable websites and applications in no time, with full support for the Universal Visual Editor (UVE).
4
+
5
+ ## Table of Contents
6
+
7
+ - [Prerequisites & Setup](#prerequisites--setup)
8
+ - [Get a dotCMS Environment](#get-a-dotcms-environment)
9
+ - [Configure The Universal Visual Editor App](#configure-the-universal-visual-editor-app)
10
+ - [Create a dotCMS API Key](#create-a-dotcms-api-key)
11
+ - [Installation](#installation)
12
+ - [dotCMS Client Configuration](#dotcms-client-configuration)
13
+ - [Proxy Configuration for Static Assets](#proxy-configuration-for-static-assets)
14
+ - [Quickstart: Render a Page with dotCMS](#quickstart-render-a-page-with-dotcms)
15
+ - [Example Project](#example-project-)
16
+ - [SDK Reference](#sdk-reference)
17
+ - [createDotCMSVue / useDotCMSClient](#createdotcmsvue--usedotcmsclient)
18
+ - [DotCMSLayoutBody](#dotcmslayoutbody)
19
+ - [DotCMSEditableText](#dotcmseditabletext)
20
+ - [DotCMSBlockEditorRenderer](#dotcmsblockeditorrenderer)
21
+ - [DotCMSShow](#dotcmsshow)
22
+ - [useEditableDotCMSPage](#useeditabledotcmspage)
23
+ - [useDotCMSShowWhen](#usedotcmsshowwhen)
24
+ - [createDotCMSImageLoader](#createdotcmsimageloader)
25
+ - [toPlain](#toplain)
26
+ - [Troubleshooting](#troubleshooting)
27
+ - [Common Issues & Solutions](#common-issues--solutions)
28
+ - [Debugging Tips](#debugging-tips)
29
+ - [Still Having Issues?](#still-having-issues)
30
+ - [Support](#support)
31
+ - [Contributing](#contributing)
32
+ - [Licensing](#licensing)
33
+
34
+ ## Prerequisites & Setup
35
+
36
+ ### Get a dotCMS Environment
37
+
38
+ #### Version Compatibility
39
+
40
+ - **Recommended**: dotCMS Evergreen
41
+ - **Minimum**: dotCMS v25.05
42
+ - **Best Experience**: Latest Evergreen release
43
+
44
+ #### Environment Setup
45
+
46
+ **For Production Use:**
47
+
48
+ - ☁️ [Cloud hosting options](https://www.dotcms.com/pricing) - managed solutions with SLA
49
+ - 🛠️ [Self-hosted options](https://dev.dotcms.com/docs/current-releases) - deploy on your infrastructure
50
+
51
+ **For Testing & Development:**
52
+
53
+ - 🧑🏻‍💻 [dotCMS demo site](https://demo.dotcms.com/dotAdmin/#/public/login) - perfect for trying out the SDK
54
+ - 📘 [Learn how to use the demo site](https://dev.dotcms.com/docs/demo-site)
55
+ - 📝 Read-only access, ideal for building proof-of-concepts
56
+
57
+ **For Local Development:**
58
+
59
+ - 🐳 [Docker setup guide](https://github.com/dotCMS/core/tree/main/docker/docker-compose-examples/single-node-demo-site)
60
+ - 💻 [Local installation guide](https://dev.dotcms.com/docs/quick-start-guide)
61
+
62
+ ### Configure The Universal Visual Editor App
63
+
64
+ For a step-by-step guide on setting up the Universal Visual Editor, check out our [easy-to-follow instructions](https://dev.dotcms.com/docs/uve-headless-config) and get started in no time!
65
+
66
+ When configuring the UVE app, point it at your Vue app's URL (e.g. `http://localhost:5173`):
67
+
68
+ ```json
69
+ { "config": [{ "pattern": "(.*)", "url": "http://localhost:5173" }] }
70
+ ```
71
+
72
+ ### Create a dotCMS API Key
73
+
74
+ > [!TIP]
75
+ > Make sure your API Token has read-only permissions for Pages, Folders, Assets, and Content. Using a key with minimal permissions follows security best practices.
76
+
77
+ This integration requires an API Key with read-only permissions for security best practices:
78
+
79
+ 1. Go to the **dotCMS admin panel**.
80
+ 2. Click on **System** > **Users**.
81
+ 3. Select the user you want to create the API Key for.
82
+ 4. Go to **API Access Key** and generate a new key.
83
+
84
+ For detailed instructions, please refer to the [dotCMS API Documentation - Read-only token](https://dev.dotcms.com/docs/rest-api-authentication#ReadOnlyToken).
85
+
86
+ ### Installation
87
+
88
+ ```bash
89
+ npm install @dotcms/vue@latest
90
+ ```
91
+
92
+ Requires **Vue 3.4+** (declared as a peer dependency). The install also brings in:
93
+
94
+ - `@dotcms/uve`: Enables interaction with the [Universal Visual Editor](https://dev.dotcms.com/docs/uve-headless-config) for real-time content editing
95
+ - `@dotcms/client`: Provides the core client functionality for fetching and managing dotCMS data
96
+ - `@tinymce/tinymce-vue`: Powers inline text editing in [`DotCMSEditableText`](#dotcmseditabletext)
97
+
98
+ ### dotCMS Client Configuration
99
+
100
+ Install the dotCMS Vue plugin once at startup. It builds the client and provides
101
+ it to the whole app, so components retrieve it with `useDotCMSClient()` instead
102
+ of importing a module-level singleton — the Vue analog of Angular's
103
+ `provideDotCMSClient`.
104
+
105
+ ```ts
106
+ // main.ts
107
+ import { createApp } from 'vue';
108
+ import { createDotCMSVue } from '@dotcms/vue';
109
+
110
+ import App from './App.vue';
111
+
112
+ const app = createApp(App);
113
+
114
+ app.use(
115
+ createDotCMSVue({
116
+ dotcmsUrl: import.meta.env.VITE_DOTCMS_HOST,
117
+ authToken: import.meta.env.VITE_DOTCMS_AUTH_TOKEN, // Optional for public content
118
+ siteId: import.meta.env.VITE_DOTCMS_SITE_ID, // Optional site identifier/name
119
+ requestOptions: {
120
+ // The UVE needs fresh data so in-context edits are reflected immediately.
121
+ cache: 'no-cache'
122
+ }
123
+ })
124
+ );
125
+
126
+ app.mount('#app');
127
+ ```
128
+
129
+ Then, in any component:
130
+
131
+ ```vue
132
+ <script setup lang="ts">
133
+ import { useDotCMSClient } from '@dotcms/vue';
134
+
135
+ const client = useDotCMSClient();
136
+ const { pageAsset } = await client.page.get('/');
137
+ </script>
138
+ ```
139
+
140
+ > **Using the client outside a component?** Code that runs before/outside a
141
+ > component `setup` — e.g. a Vue Router page loader — can't call
142
+ > `useDotCMSClient()`. Keep a reference to the plugin and read its `.client`:
143
+ >
144
+ > ```ts
145
+ > export const dotCMSVue = createDotCMSVue({ ...config });
146
+ > export const dotCMSClient = dotCMSVue.client; // same instance the plugin provides
147
+ > ```
148
+
149
+ If you prefer to manage the client yourself, `createDotCMSClient` from
150
+ `@dotcms/client` is still available and works with all of this SDK's components
151
+ and composables — the plugin is a convenience, not a requirement.
152
+
153
+ ```typescript
154
+ import { createDotCMSClient } from '@dotcms/client';
155
+
156
+ export const dotCMSClient = createDotCMSClient({
157
+ dotcmsUrl: import.meta.env.VITE_DOTCMS_HOST,
158
+ authToken: import.meta.env.VITE_DOTCMS_AUTH_TOKEN,
159
+ siteId: import.meta.env.VITE_DOTCMS_SITE_ID,
160
+ requestOptions: { cache: 'no-cache' }
161
+ });
162
+ ```
163
+
164
+ ### Proxy Configuration for Static Assets
165
+
166
+ Configure a proxy to leverage the powerful dotCMS image API, allowing you to resize and serve optimized images efficiently. This enhances application performance and improves the user experience.
167
+
168
+ #### 1. Configure Vite
169
+
170
+ ```ts
171
+ // vite.config.ts
172
+ import { defineConfig } from 'vite';
173
+
174
+ export default defineConfig({
175
+ server: {
176
+ proxy: {
177
+ '/dA': {
178
+ target: 'https://your-dotcms-instance.com',
179
+ changeOrigin: true
180
+ }
181
+ }
182
+ }
183
+ });
184
+ ```
185
+
186
+ Learn more about Vite configuration [here](https://vitejs.dev/config/).
187
+
188
+ #### 2. Usage in Components
189
+
190
+ Once configured, image URLs in your components will automatically be proxied to your dotCMS instance:
191
+
192
+ > 📚 Learn more about [Image Resizing and Processing in dotCMS](https://www.dotcms.com/blog/image-resizing-and-processing-in-dotcms-with-angular-and-nextjs).
193
+
194
+ ```vue
195
+ <script setup lang="ts">
196
+ import type { DotCMSBasicContentlet } from '@dotcms/types';
197
+
198
+ defineProps<{ contentlet: DotCMSBasicContentlet }>();
199
+ </script>
200
+
201
+ <template>
202
+ <img :src="`/dA/${contentlet.inode}`" :alt="contentlet.title" />
203
+ </template>
204
+ ```
205
+
206
+ ## Quickstart: Render a Page with dotCMS
207
+
208
+ The following example shows how to quickly set up a basic dotCMS page renderer in your Vue application. It demonstrates how to:
209
+
210
+ - Fetch a dotCMS page and render it with `DotCMSLayoutBody`
211
+ - Map content types to your own Vue components
212
+ - Keep the page editable and live-updating inside the Universal Visual Editor
213
+
214
+ Because a Vue composable must be called synchronously in `setup`, the recommended pattern splits fetching from rendering: a **fetcher** loads the page, then mounts a **renderer** child that receives the resolved page and calls `useEditableDotCMSPage`.
215
+
216
+ ```vue
217
+ <!-- PageView.vue — fetches the page, then mounts the renderer -->
218
+ <script setup lang="ts">
219
+ import { shallowRef, onMounted } from 'vue';
220
+
221
+ import PageRenderer from './PageRenderer.vue';
222
+ import { dotCMSClient } from './dotCMSClient';
223
+
224
+ // shallowRef keeps the response a plain object (see toPlain / reactivity note below).
225
+ const pageResponse = shallowRef<Awaited<ReturnType<typeof dotCMSClient.page.get>> | null>(null);
226
+
227
+ onMounted(async () => {
228
+ pageResponse.value = await dotCMSClient.page.get('/');
229
+ });
230
+ </script>
231
+
232
+ <template>
233
+ <PageRenderer v-if="pageResponse" :page-response="pageResponse" />
234
+ </template>
235
+ ```
236
+
237
+ ```vue
238
+ <!-- PageRenderer.vue — renders the resolved page -->
239
+ <script setup lang="ts">
240
+ import { DotCMSLayoutBody, useEditableDotCMSPage } from '@dotcms/vue';
241
+ import { computed } from 'vue';
242
+
243
+ import Blog from './content-types/Blog.vue';
244
+ import Product from './content-types/Product.vue';
245
+
246
+ const props = defineProps<{ pageResponse: unknown }>();
247
+
248
+ const pageComponents = {
249
+ Blog,
250
+ Product
251
+ };
252
+
253
+ // Returns a reactive ref that live-updates while editing in the UVE.
254
+ const page = useEditableDotCMSPage(props.pageResponse as never);
255
+ const pageAsset = computed(() => page.value?.pageAsset);
256
+ </script>
257
+
258
+ <template>
259
+ <DotCMSLayoutBody v-if="pageAsset" :page="pageAsset" :components="pageComponents" />
260
+ </template>
261
+ ```
262
+
263
+ ### Example Project 🚀
264
+
265
+ Looking to get started quickly? Our [Vue.js starter project](https://github.com/dotCMS/core/tree/main/examples/vuejs) is the perfect launchpad. This Vite + TypeScript + Tailwind template demonstrates everything you need:
266
+
267
+ 📦 Fetch and render dotCMS pages with best practices
268
+ 🧩 Map components to different content types
269
+ 🔍 Listing pages with search functionality
270
+ 📝 Detail pages with the block editor
271
+ 📈 Image and asset optimization for better performance
272
+ ✨ Seamless editing via the Universal Visual Editor (UVE)
273
+ ⚡️ Vue Composition API + reactive live updates
274
+
275
+ ## SDK Reference
276
+
277
+ All components, composables and utilities are imported from `@dotcms/vue`.
278
+
279
+ ### createDotCMSVue / useDotCMSClient
280
+
281
+ `createDotCMSVue(config)` returns a Vue plugin that builds a dotCMS client and
282
+ provides it app-wide. `useDotCMSClient()` retrieves that client from any
283
+ component. See [dotCMS Client Configuration](#dotcms-client-configuration) for
284
+ the full setup.
285
+
286
+ ```ts
287
+ import { createDotCMSVue } from '@dotcms/vue';
288
+
289
+ const plugin = createDotCMSVue({ dotcmsUrl, authToken /* …DotCMSClientConfig */ });
290
+ app.use(plugin);
291
+ ```
292
+
293
+ | Export | Signature | Description |
294
+ | ------------------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
295
+ | `createDotCMSVue(config)` | `(config: DotCMSClientConfig) => DotCMSVuePlugin` | Vue plugin for `app.use()`. `config` is the same object accepted by `createDotCMSClient`. |
296
+ | `useDotCMSClient()` | `() => DotCMSClient` | Returns the provided client. Throws if the plugin was not installed. Call it inside `setup`. |
297
+ | `DotCMSVuePlugin.client` | `DotCMSClient` | The created client instance, for use outside components (e.g. router loaders). |
298
+
299
+ ### DotCMSLayoutBody
300
+
301
+ `DotCMSLayoutBody` renders the layout for a dotCMS page (rows → columns → containers → contentlets), dispatching each contentlet to the mapped component. It supports both production and development modes.
302
+
303
+ | Prop | Type | Required | Default | Description |
304
+ | ------------ | -------------------------- | -------- | -------------- | -------------------------------------------------------------------- |
305
+ | `page` | `DotCMSPageAsset` | ✅ | - | The page asset containing the layout to render |
306
+ | `components` | `Record<string, Component>`| ✅ | `{}` | [Map of content type → Vue component](#component-mapping) |
307
+ | `mode` | `DotCMSPageRendererMode` | ❌ | `'production'` | [Rendering mode ('production' or 'development')](#layout-body-modes) |
308
+
309
+ #### Usage
310
+
311
+ ```vue
312
+ <script setup lang="ts">
313
+ import { DotCMSLayoutBody } from '@dotcms/vue';
314
+ import type { DotCMSPageAsset } from '@dotcms/types';
315
+
316
+ import Blog from './content-types/Blog.vue';
317
+ import Product from './content-types/Product.vue';
318
+
319
+ defineProps<{ page: DotCMSPageAsset }>();
320
+
321
+ const components = {
322
+ Blog,
323
+ Product
324
+ };
325
+ </script>
326
+
327
+ <template>
328
+ <DotCMSLayoutBody :page="page" :components="components" />
329
+ </template>
330
+ ```
331
+
332
+ #### Layout Body Modes
333
+
334
+ - `production`: Performance-optimized mode that only renders content with explicitly mapped components, leaving unmapped content empty.
335
+ - `development`: Debug-friendly mode that renders a fallback for unmapped content types and shows visual indicators for empty containers and missing mappings. **Inside the UVE, edit mode is detected automatically** — the editor `data-dot-*` metadata is always emitted regardless of the `mode` prop.
336
+
337
+ #### Component Mapping
338
+
339
+ The `components` prop maps content type variable names to Vue components. Each contentlet's fields are passed to the matched component as props.
340
+
341
+ ```typescript
342
+ const components = {
343
+ Blog: MyBlogCard,
344
+ Product: MyProductCard,
345
+ CustomNoComponent: MyFallback // optional: rendered for unmapped types in dev mode
346
+ };
347
+ ```
348
+
349
+ - Keys (e.g. `Blog`, `Product`): must match your [content type variable names](https://dev.dotcms.com/docs/content-types#VariableNames) in dotCMS (they are case-sensitive — e.g. `webPageContent`, `calendarEvent`).
350
+ - Values: the Vue component that renders that content type. Declare a typed props interface for the fields you use — do **not** spread the full `DotCMSBasicContentlet` type onto a component, as Vue runtime-validates every declared prop and dotCMS ships some fields (e.g. `language`, `modDate`) with types that differ from the type defs.
351
+ - The special `CustomNoComponent` key is the fallback rendered when no mapping exists.
352
+
353
+ > [!TIP]
354
+ > Always use the exact content type variable name from dotCMS as the key. You can find it in the Content Types section of your dotCMS admin panel.
355
+
356
+ #### Per-contentlet slots
357
+
358
+ Beyond mapping by content type, you can override a **specific** contentlet by
359
+ its `identifier` using a named slot: `#contentlet-<identifier>`. When present,
360
+ the slot renders instead of the mapped component — the Vue analog of the React
361
+ SDK's `slots` prop, useful for one-off custom markup or a pre-rendered node.
362
+
363
+ The contentlet is exposed as the slot's scope prop.
364
+
365
+ ```vue
366
+ <template>
367
+ <DotCMSLayoutBody :page="page" :components="components">
368
+ <!-- Renders instead of the Blog component for this one contentlet -->
369
+ <template #contentlet-a1b2c3d4="{ contentlet }">
370
+ <FeaturedBlog :blog="contentlet" />
371
+ </template>
372
+ </DotCMSLayoutBody>
373
+ </template>
374
+ ```
375
+
376
+ Contentlets without a matching slot fall back to the `components` mapping as usual.
377
+
378
+ ### DotCMSEditableText
379
+
380
+ `DotCMSEditableText` enables inline editing of a single text field in dotCMS. Inside the UVE in edit mode it mounts a TinyMCE editor; everywhere else it renders the field's current value.
381
+
382
+ | Prop | Type | Required | Default | Description |
383
+ | ------------ | ----------------------------- | -------- | --------- | ------------------------------------------------------------------ |
384
+ | `contentlet` | `T extends DotCMSBasicContentlet` | ✅ | - | The contentlet containing the editable field |
385
+ | `fieldName` | `keyof T` | ✅ | - | Name of the field to edit (must be a valid key of the contentlet) |
386
+ | `mode` | `'plain' \| 'minimal' \| 'full'` | ❌ | `'plain'` | TinyMCE toolbar preset. `full` enables the full style bubble menu. |
387
+ | `format` | `'text' \| 'html'` | ❌ | `'text'` | `text` renders HTML as plain text; `html` interprets HTML markup |
388
+
389
+ #### Usage
390
+
391
+ ```vue
392
+ <script setup lang="ts">
393
+ import { DotCMSEditableText } from '@dotcms/vue';
394
+ import type { DotCMSBasicContentlet } from '@dotcms/types';
395
+
396
+ const props = defineProps<{ contentlet: DotCMSBasicContentlet }>();
397
+ </script>
398
+
399
+ <template>
400
+ <div class="banner">
401
+ <img :src="`/dA/${contentlet.inode}`" :alt="contentlet.title" />
402
+ <h2>
403
+ <DotCMSEditableText :contentlet="contentlet" field-name="title" />
404
+ </h2>
405
+ </div>
406
+ </template>
407
+ ```
408
+
409
+ #### Editor Integration
410
+
411
+ - Detects UVE edit mode and enables inline TinyMCE editing.
412
+ - Sends the edited content back to the editor on blur, without opening the full content dialog.
413
+ - The TinyMCE script is loaded from your dotCMS instance (`dotCMSHost`), so no extra TinyMCE install is required.
414
+
415
+ ### DotCMSBlockEditorRenderer
416
+
417
+ `DotCMSBlockEditorRenderer` renders [Block Editor](https://dev.dotcms.com/docs/block-editor) content from dotCMS, with support for custom block renderers.
418
+
419
+ | Prop | Type | Required | Default | Description |
420
+ | ----------------- | --------------------------- | -------- | ------- | --------------------------------------------------------------- |
421
+ | `blocks` | `BlockEditorNode` | ✅ | - | The Block Editor field value to render |
422
+ | `customRenderers` | `CustomRenderer` | ❌ | - | Custom Vue components for specific block types / content types |
423
+ | `className` | `string` | ❌ | - | CSS class applied to the container |
424
+ | `style` | `CSSProperties` | ❌ | - | Inline styles for the container |
425
+ | `isDevMode` | `boolean` | ❌ | `false` | When `true`, shows a visible message for invalid/unknown blocks |
426
+
427
+ > **`className`/`style` vs native `class`/`style`:** the `className` and `style`
428
+ > props mirror the React SDK so the same code shape works across frameworks. This
429
+ > component renders one of two root elements (an error box or the content
430
+ > container), so Vue's automatic attribute fallthrough does **not** apply — a
431
+ > native `class="prose"` on the tag will not reach the container. Use the
432
+ > `className` and `style` props to style the container:
433
+ >
434
+ > ```vue
435
+ > <DotCMSBlockEditorRenderer
436
+ > :blocks="contentlet.body"
437
+ > class-name="prose max-w-none"
438
+ > :style="{ marginTop: '1rem' }" />
439
+ > ```
440
+
441
+ #### Usage
442
+
443
+ A custom renderer is a Vue component that receives the block as a `node` prop and the rendered children in its default `<slot />`.
444
+
445
+ ```vue
446
+ <!-- CustomHeading.vue -->
447
+ <script setup lang="ts">
448
+ import type { CustomRendererProps } from '@dotcms/vue';
449
+
450
+ defineProps<CustomRendererProps>();
451
+ </script>
452
+
453
+ <template>
454
+ <h1 class="my-heading"><slot /></h1>
455
+ </template>
456
+ ```
457
+
458
+ ```vue
459
+ <!-- DetailPage.vue -->
460
+ <script setup lang="ts">
461
+ import { DotCMSBlockEditorRenderer, type CustomRenderer } from '@dotcms/vue';
462
+ import type { DotCMSBasicContentlet } from '@dotcms/types';
463
+
464
+ import CustomHeading from './CustomHeading.vue';
465
+
466
+ const props = defineProps<{ contentlet: DotCMSBasicContentlet }>();
467
+
468
+ const customRenderers: CustomRenderer = {
469
+ heading: CustomHeading
470
+ };
471
+ </script>
472
+
473
+ <template>
474
+ <DotCMSBlockEditorRenderer
475
+ :blocks="contentlet.myBlockEditorField"
476
+ :custom-renderers="customRenderers" />
477
+ </template>
478
+ ```
479
+
480
+ #### Recommendations
481
+
482
+ - Should not be used together with [`DotCMSEditableText`](#dotcmseditabletext) on the same field.
483
+ - Be mindful that the CSS cascade can affect the look and feel of your blocks.
484
+ - Only works with [Block Editor fields](https://dev.dotcms.com/docs/block-editor). For other text fields, use [`DotCMSEditableText`](#dotcmseditabletext).
485
+
486
+ ### DotCMSShow
487
+
488
+ `DotCMSShow` conditionally renders its slot content based on the current UVE mode — useful for editor-only affordances like Edit or Reorder buttons.
489
+
490
+ | Prop | Type | Required | Default | Description |
491
+ | ------ | ---------- | -------- | ---------------- | -------------------------------------------------------- |
492
+ | `when` | `UVE_MODE` | ❌ | `UVE_MODE.EDIT` | The UVE mode in which the slot content should be shown |
493
+
494
+ #### Usage
495
+
496
+ ```vue
497
+ <script setup lang="ts">
498
+ import { DotCMSShow } from '@dotcms/vue';
499
+ import { UVE_MODE } from '@dotcms/types';
500
+ </script>
501
+
502
+ <template>
503
+ <DotCMSShow :when="UVE_MODE.EDIT">
504
+ <button>Edit</button>
505
+ </DotCMSShow>
506
+ </template>
507
+ ```
508
+
509
+ 📚 Learn more about the `UVE_MODE` enum in the [dotCMS UVE documentation](https://dev.dotcms.com/docs/universal-visual-editor).
510
+
511
+ ### useEditableDotCMSPage
512
+
513
+ `useEditableDotCMSPage` wires a page into the Universal Visual Editor and returns a reactive ref that live-updates as an editor makes changes. Outside the UVE it is a pass-through — the returned ref simply holds the initial response.
514
+
515
+ | Param | Type | Required | Description |
516
+ | -------------- | ----------------------------- | -------- | --------------------------------------------- |
517
+ | `pageResponse` | `DotCMSComposedPageResponse` | ✅ | The page response from `client.page.get()` |
518
+
519
+ **Returns** a `Ref<DotCMSComposedPageResponse>` — access `.value.pageAsset` and `.value.content`.
520
+
521
+ When you use the composable, it:
522
+
523
+ 1. Initializes the UVE with your page data
524
+ 2. Keeps the editor navigation in sync
525
+ 3. Subscribes to content changes and swaps in the new page automatically when content is edited, blocks are added/removed, layout changes, or components are moved
526
+ 4. Cleans up all listeners on unmount
527
+
528
+ #### Usage
529
+
530
+ ```vue
531
+ <script setup lang="ts">
532
+ import { DotCMSLayoutBody, useEditableDotCMSPage } from '@dotcms/vue';
533
+ import { computed } from 'vue';
534
+
535
+ const props = defineProps<{ pageResponse: unknown }>();
536
+
537
+ const page = useEditableDotCMSPage(props.pageResponse as never);
538
+ const pageAsset = computed(() => page.value?.pageAsset);
539
+
540
+ const components = {
541
+ /* content-type → component map */
542
+ };
543
+ </script>
544
+
545
+ <template>
546
+ <DotCMSLayoutBody v-if="pageAsset" :page="pageAsset" :components="components" />
547
+ </template>
548
+ ```
549
+
550
+ > [!IMPORTANT]
551
+ > Store the page response in a `shallowRef` (not a deep `ref`). A deep `ref` wraps the whole page in reactive Proxies, which the UVE cannot `postMessage` to the editor (`DataCloneError`). See [`toPlain`](#toplain).
552
+
553
+ ### useDotCMSShowWhen
554
+
555
+ `useDotCMSShowWhen` returns a reactive boolean for whether the current UVE mode matches — useful for mode-based logic outside of the template.
556
+
557
+ | Param | Type | Required | Description |
558
+ | ------ | ---------- | -------- | ---------------------------------- |
559
+ | `when` | `UVE_MODE` | ✅ | The UVE mode to check against |
560
+
561
+ #### Usage
562
+
563
+ ```vue
564
+ <script setup lang="ts">
565
+ import { useDotCMSShowWhen } from '@dotcms/vue';
566
+ import { UVE_MODE } from '@dotcms/types';
567
+
568
+ const isEditMode = useDotCMSShowWhen(UVE_MODE.EDIT); // Readonly<Ref<boolean>>
569
+ </script>
570
+
571
+ <template>
572
+ <button v-if="isEditMode">Edit</button>
573
+ </template>
574
+ ```
575
+
576
+ ### createDotCMSImageLoader
577
+
578
+ `createDotCMSImageLoader(dotcmsUrl?)` returns a function that turns a dotCMS asset identifier (or path) into an optimized image URL via the dotCMS image API (the `/dA/` route, which handles resizing and optimization). It's the Vue analog of Angular's `provideDotCMSImageLoader` — Vue has no `IMAGE_LOADER` token, so you call the returned function directly.
579
+
580
+ Absolute `http(s)://…` URLs are returned unchanged, so mixing dotCMS assets with external/stock imagery just works.
581
+
582
+ | Argument | Type | Required | Default | Description |
583
+ | ----------- | -------- | -------- | ------- | ---------------------------------------------------------------------------------------- |
584
+ | `dotcmsUrl` | `string` | ❌ | `''` | Base URL of your dotCMS instance. Omit (empty) for site-relative `/dA/…` behind a proxy. |
585
+
586
+ The returned loader is `(src: string, options?) => string`, where `options` is `{ width?, quality?, languageId? }` (`quality` defaults to `50`, `languageId` to `'1'`).
587
+
588
+ ```ts
589
+ import { createDotCMSImageLoader } from '@dotcms/vue';
590
+
591
+ // Absolute (production)
592
+ const image = createDotCMSImageLoader(import.meta.env.VITE_DOTCMS_HOST);
593
+ image(contentlet.inode, { width: 800 });
594
+ // → https://demo.dotcms.com/dA/<inode>/800w/50q?language_id=1
595
+
596
+ // Site-relative (dev proxy) — omit the host so the Vite /dA proxy handles it
597
+ const proxied = createDotCMSImageLoader();
598
+ proxied(contentlet.inode, { width: 800 }); // → /dA/<inode>/800w/50q?language_id=1
599
+ ```
600
+
601
+ ```vue
602
+ <script setup lang="ts">
603
+ import { createDotCMSImageLoader } from '@dotcms/vue';
604
+ import type { DotCMSBasicContentlet } from '@dotcms/types';
605
+
606
+ const props = defineProps<{ contentlet: DotCMSBasicContentlet }>();
607
+
608
+ const image = createDotCMSImageLoader(import.meta.env.VITE_DOTCMS_HOST);
609
+ </script>
610
+
611
+ <template>
612
+ <img :src="image(contentlet.inode, { width: 800 })" :alt="contentlet.title" />
613
+ </template>
614
+ ```
615
+
616
+ ### toPlain
617
+
618
+ `toPlain` deep-unwraps a Vue reactive value (refs / reactive proxies) into a plain, structured-clone-safe object. Use it before passing reactive data to UVE editor actions (`editContentlet`, `enableBlockEditorInline`, …) from `@dotcms/uve`, which send their argument to the editor via `postMessage`.
619
+
620
+ ```vue
621
+ <script setup lang="ts">
622
+ import { toPlain } from '@dotcms/vue';
623
+ import { editContentlet } from '@dotcms/uve';
624
+ import type { DotCMSBasicContentlet } from '@dotcms/types';
625
+
626
+ const props = defineProps<{ contentlet: DotCMSBasicContentlet }>();
627
+
628
+ const onEdit = () => editContentlet(toPlain(props.contentlet));
629
+ </script>
630
+ ```
631
+
632
+ ## Troubleshooting
633
+
634
+ ### Common Issues & Solutions
635
+
636
+ #### Universal Visual Editor (UVE)
637
+
638
+ 1. **UVE not loading**: the page renders but the editor tools/overlays don't appear.
639
+ - **Possible causes**: incorrect UVE app configuration; missing `useEditableDotCMSPage`; the app is not running inside the UVE iframe.
640
+ - **Solutions**: verify the UVE app URL matches your Vue dev server; ensure the page tree is wrapped with `useEditableDotCMSPage`; confirm `data-dot-object="contentlet"` attributes are present on rendered contentlets (they only appear in edit mode).
641
+
642
+ 2. **`DataCloneError: could not be cloned`** when loading in the editor.
643
+ - **Cause**: a Vue reactive Proxy was sent to the editor via `postMessage`.
644
+ - **Solutions**: store the page response in a `shallowRef`, not a deep `ref`; use [`toPlain`](#toplain) before calling UVE editor actions with reactive data.
645
+
646
+ 3. **Content edits don't update the page live.**
647
+ - **Cause**: usually a duplicate Vue instance — if `vue` is bundled into a consumer copy, the SDK's reactivity is a different instance from your app's. Ensure a single `vue` is installed.
648
+
649
+ #### Missing Content
650
+
651
+ 1. **Components not rendering**: empty spaces where content should appear.
652
+ - **Solutions**: check the `components` map registration; verify content type variable names match exactly (case-sensitive); use `mode="development"` for detailed logging.
653
+
654
+ 2. **Prop validation warnings** (e.g. *Invalid prop: type check failed for prop "modDate"*).
655
+ - **Cause**: a content-type component declares props by extending the full contentlet type; dotCMS ships some system fields with types that differ from the defs.
656
+ - **Solution**: declare only the specific fields your component reads.
657
+
658
+ #### Development Setup
659
+
660
+ 1. **`npm install` fails**: clear the npm cache (`npm cache clean --force`), delete `node_modules`, and reinstall; verify your Node.js version.
661
+
662
+ 2. **Runtime errors about missing imports**: check that all SDK imports come from `@dotcms/vue`, and that peer dependencies (`vue`, `@dotcms/client`, `@dotcms/uve`, `@dotcms/types`) are installed.
663
+
664
+ ### Debugging Tips
665
+
666
+ 1. **Enable development mode**
667
+
668
+ ```vue
669
+ <DotCMSLayoutBody :page="pageAsset" :components="components" mode="development" />
670
+ ```
671
+
672
+ This shows detailed messages, renders fallbacks for unmapped components, and highlights empty containers.
673
+
674
+ 2. **Check the browser console and network tab** for errors, and watch for 401/403 (auth) responses.
675
+
676
+ 3. **Inspect the DOM** inside the UVE iframe — contentlets should carry `data-dot-object="contentlet"` and containers `data-dot-object="container"` in edit mode.
677
+
678
+ ### Still Having Issues?
679
+
680
+ If you're still experiencing problems after trying these solutions:
681
+
682
+ 1. Search existing [GitHub issues](https://github.com/dotCMS/core/issues)
683
+ 2. Ask questions on the [community forum](https://community.dotcms.com/)
684
+ 3. Create a new issue with detailed reproduction steps, environment information, error messages, and code samples
685
+
686
+ ## Support
687
+
688
+ We offer multiple channels to get help with the dotCMS Vue SDK:
689
+
690
+ - **GitHub Issues**: For bug reports and feature requests, please [open an issue](https://github.com/dotCMS/core/issues/new/choose).
691
+ - **Community Forum**: Join our [community discussions](https://community.dotcms.com/).
692
+ - **Enterprise Support**: Enterprise customers can access premium support through the [dotCMS Support Portal](https://www.dotcms.com/support).
693
+
694
+ When reporting issues, please include:
695
+
696
+ - SDK version you're using
697
+ - Vue version
698
+ - Minimal reproduction steps
699
+ - Expected vs. actual behavior
700
+
701
+ ## Contributing
702
+
703
+ GitHub pull requests are the preferred method to contribute code to dotCMS. We welcome contributions to the dotCMS Vue SDK! If you'd like to contribute, please:
704
+
705
+ 1. Fork the repository [dotCMS/core](https://github.com/dotCMS/core)
706
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
707
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
708
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
709
+ 5. Open a Pull Request
710
+
711
+ Please ensure your code follows the existing style and includes appropriate tests.
712
+
713
+ ## Licensing
714
+
715
+ dotCMS is available under either the [Business Source License 1.1 (BSL)](https://www.dotcms.com/bsl) or a commercial license.
716
+
717
+ Under the BSL, dotCMS can be used at no cost by individual developers, small businesses or agencies under $5M in total finances, and by larger organizations in non-production environments. Every BSL release automatically converts to GPL v3 four years after its release date. For full terms and FAQs, visit [dotcms.com/bsl](https://www.dotcms.com/bsl) and [dotcms.com/bsl-faq](https://www.dotcms.com/bsl-faq).
718
+
719
+ Production use in larger organizations, along with access to managed cloud, SLAs, support, and enterprise capabilities, is available under a commercial license from dotCMS. For details on commercial plans, features, and support options, see [dotcms.com/pricing](https://www.dotcms.com/pricing).