---
title: Vue
description: Render what you publish in a Vue 3 app with @hollware/vue, from a server that renders Vue or from a browser-only app with a read token.
section: frameworks
order: 4
---

# Vue

`@hollware/vue` is for a Vue 3 app that is not Nuxt (for Nuxt, use [`@hollware/nuxt`](/docs/nuxt/)). Its components render entries with your own Vue components, on the server and in the browser, and its composables read published content from a browser-only app.

```sh
npm install @hollware/vue
```

## A browser-only app

The composables read over HTTP with a **read token** (`npx hollware token create --read`). The token is in the page, so anyone can read it: it reads published content and nothing else. Hollware accepts it only from the origins of the site's **Origins that read from the browser**, in the admin under **Site**: add your app's, and `http://localhost:5173` for development.

```ts
// main.ts
import { createHollwarePlugin } from '@hollware/vue'

createApp(App)
  .use(createHollwarePlugin({ site: 'my-site', url: 'https://cms.example.com', token: 'hw_read_…' }))
  .mount('#app')
```

```vue
<script setup lang="ts">
import { HollwareContent, HollwareImage, useHollwareEntry } from '@hollware/vue'

const props = defineProps<{ slug: string }>()
const { data, error, pending } = useHollwareEntry('blog', 'en', () => props.slug)
</script>

<template>
  <p v-if="pending">Loading…</p>
  <p v-else-if="error">{{ error.message }}</p>
  <article v-else-if="data">
    <HollwareImage :entry="data" field="img" />
    <HollwareContent :entry="data" :components="{ callout: Callout }" />
  </article>
  <p v-else>Not found</p>
</template>
```

| Composable | Gives |
| --- | --- |
| `useHollwareEntry(collection, locale, slug)` | `{ data, error, pending }` for one published entry; each argument may be a ref or a getter |
| `useHollwareEntries(collection, { locale, tag, limit, cursor })` | `{ data, error, pending }` for a page of entries, newest first |

When an argument changes, the composable reads again and keeps the previous `data` meanwhile. A browser-only app has no previews: the preview link becomes a cookie that only a server can read.

## A server that renders Vue

On Vite SSR, Vike or any server of your own, the server helpers are those of [React](/docs/react/), re-exported: `createHollware`, `getEntry`, `listEntries`, `previewRedirect` and `previewHeaders`, over a service binding or a read token. Render the entry on the server with `<HollwareContent :entry>` and send the same entry to the browser to hydrate. Previews work as in React.

## The components

- **`<HollwareContent :entry :components>`** renders the entry from the document Hollware stored when it was written: no Markdown parser reaches the page. `components` maps the components of your entries (`::callout` is `callout`) to your own Vue components; anything else renders as its plain tag. Its images come with their `srcset`, `sizes`, `width` and `height`.
- **`<HollwareImage :entry field>`** renders the image a frontmatter field holds, with its alt, its size and the `srcset` of its copies. Any attribute you give wins.
