Framework guides

Vue

@scribe-atp/vue provides useScribeSite and useScribeArticle composables for Vue 3. Each composable returns reactive refs for site/article, loading, and error, and aborts the in-flight request when the component is unmounted.

Note

For Nuxt 3, use @scribe-atp/nuxt instead — it wraps these composables with useAsyncData for SSR support and auto-imports.

Install

npm install @scribe-atp/vue

Requires Vue 3 or later.

useScribeSite

<script setup lang="ts">
import { useScribeSite } from '@scribe-atp/vue';

const { site, loading, error } = useScribeSite('alice.bsky.social', 'https://alice.bsky.social');
</script>

<template>
  <p v-if="loading">Loading…</p>
  <p v-else-if="error">Error: {{ error.message }}</p>
  <main v-else-if="site">
    <h1>{{ site.title }}</h1>
    <section v-for="group in site.groups" :key="group.slug">
      <h2>{{ group.title }}</h2>
      <ul>
        <li v-for="article in group.articles" :key="article.uri">
          <a :href="`/${group.slug}/${article.slug}`">{{ article.title }}</a>
        </li>
      </ul>
    </section>
  </main>
</template>

useScribeArticle

<script setup lang="ts">
import { useScribeArticle } from '@scribe-atp/vue';

const props = defineProps<{ author: string; slug: string }>();
const { article, loading, error } = useScribeArticle(props.author, props.slug);
</script>

<template>
  <p v-if="loading">Loading…</p>
  <p v-else-if="error">Error: {{ error.message }}</p>
  <article v-else-if="article">
    <h1>{{ article.title }}</h1>
    <p v-if="article.description">{{ article.description }}</p>
    <div v-html="article.content" />
  </article>
</template>

Just the AT URI — useScribePublicationUri / useScribeDocumentUri

@scribe-atp/social's LikeButton, SubscribeButton, and ShareButton are React components, so they aren't directly usable from a Vue template — but if you're building your own like/subscribe UI against the AT Protocol yourself, useScribePublicationUri and useScribeDocumentUri resolve just the AT URI without fetching (or reacting to) the full site/article object:

<script setup lang="ts">
import { useScribeArticle, useScribeDocumentUri } from '@scribe-atp/vue';

const props = defineProps<{ author: string; publicationUrl: string; slug: string }>();
const { article, loading } = useScribeArticle(props.author, props.slug);
const { uri } = useScribeDocumentUri(props.author, props.publicationUrl, props.slug);
</script>

<template>
  <p v-if="loading">Loading…</p>
  <article v-else-if="article">
    <h1>{{ article.title }}</h1>
    <div v-html="article.content" />
  </article>
  <p v-if="uri">AT URI: {{ uri }}</p>
</template>

TypeScript types

All types from @scribe-atp/core are re-exported from @scribe-atp/vue:

import type { Site, Article, ArticleRef, SiteGroup } from '@scribe-atp/vue';

Settings

Appearance