Advanced
Customizing the theme components
The components used by the Twitter theme allow some simple customization options for common use cases. However you can also have full control over the tweet by building your own Tweet component with the components and features of the theme that you would like to use.
For example, you can build your own tweet component but without the reply button like so:
MyTweet.vue
<script setup lang="ts">
import { computed } from 'vue'
import type { Tweet } from 'vue-better-tweet/api'
import {
type TwitterComponents,
TweetContainer,
TweetHeader,
TweetInReplyTo,
TweetBody,
TweetMedia,
TweetInfo,
TweetActions,
QuotedTweet,
enrichTweet,
} from 'rvue-better-tweet'
type Props = {
tweet: Tweet
components?: TwitterComponents
}
const props = defineProps<Props>()
const tweet = computed(() => enrichTweet(props.tweet))
</script>
<template>
<TweetContainer>
<TweetHeader :tweet="tweet" :components="props.components" />
<TweetInReplyTo v-if="tweet.in_reply_to_status_id_str" :tweet="tweet" />
<TweetBody :tweet="tweet" />
<TweetMedia
v-if="tweet.mediaDetails?.length"
:tweet="tweet"
:components="props.components"
/>
<QuotedTweet v-if="tweet.quoted_tweet" :tweet="tweet.quoted_tweet" />
<TweetInfo :tweet="tweet" />
<TweetActions :tweet="tweet" />
<!-- We're not including the `TweetReplies` component that adds the reply button -->
</TweetContainer>
</template>Then, you can build your own Tweet component that uses the MyTweet component:
Tweet.vue
<script setup lang="ts">
import { onServerPrefetch, ref } from 'vue'
import { getTweet } from 'vue-better-tweet/api'
import { type TweetProps, TweetNotFound, TweetSkeleton } from 'vue-better-tweet'
import MyTweet from './MyTweet.vue'
const props = withDefaults(defineProps<TweetProps>(), {
fallback: () => TweetSkeleton,
})
const tweet = ref()
const error = ref<unknown>()
onServerPrefetch(async () => {
if (!props.id) return
try {
tweet.value = await getTweet(props.id)
} catch (err) {
error.value = err
if (props.onError) {
props.onError(err)
} else {
console.error(err)
}
}
})
</script>
<template>
<Suspense>
<template #default>
<component
:is="props.components?.TweetNotFound || TweetNotFound"
v-if="!tweet"
/>
<MyTweet v-else :tweet="tweet" :components="props.components" />
</template>
<template #fallback>
<component :is="props.fallback" />
</template>
</Suspense>
</template>The Tweet component uses Suspense to progressively load the tweet (non-blocking rendering) and to opt-in into streaming if your framework supports it, like Nuxt.
If your framework does not support server components or async component setup for server rendering, you can use SWRV (opens in a new tab) instead:
Tweet.client.vue
<script setup lang="ts">
import { computed } from 'vue'
import {
type TweetProps,
EmbeddedTweet,
TweetNotFound,
TweetSkeleton,
useTweet,
} from 'vue-better-tweet'
const props = withDefaults(defineProps<TweetProps>(), {
fallback: () => TweetSkeleton,
})
const { data, error, isLoading } = useTweet(props.id, props.apiUrl)
const notFound = computed(
() => (props.components?.TweetNotFound || TweetNotFound),
)
</script>
<template>
<component :is="props.fallback" v-if="isLoading" />
<component
:is="notFound"
v-else-if="error || !data"
:error="props.onError ? props.onError(error) : error"
/>
<EmbeddedTweet v-else :tweet="data" :components="props.components" />
</template>