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:

my-tweet.tsx
import type { Tweet } from 'react-tweet/api'
import {
  type TwitterComponents,
  TweetContainer,
  TweetHeader,
  TweetInReplyTo,
  TweetBody,
  TweetMedia,
  TweetInfo,
  TweetActions,
  QuotedTweet,
  enrichTweet,
} from 'react-tweet'
 
type Props = {
  tweet: Tweet
  components?: TwitterComponents
}
 
export const MyTweet = ({ tweet: t, components }: Props) => {
  const tweet = enrichTweet(t)
  return (
    <TweetContainer>
      <TweetHeader tweet={tweet} components={components} />
      {tweet.in_reply_to_status_id_str && <TweetInReplyTo tweet={tweet} />}
      <TweetBody tweet={tweet} />
      {tweet.mediaDetails?.length ? (
        <TweetMedia tweet={tweet} components={components} />
      ) : null}
      {tweet.quoted_tweet && <QuotedTweet tweet={tweet.quoted_tweet} />}
      <TweetInfo tweet={tweet} />
      <TweetActions tweet={tweet} />
      {/* We're not including the `TweetReplies` component that adds the reply button */}
    </TweetContainer>
  )
}

Then, you can build your own Tweet component that uses the MyTweet component:

tweet.tsx
import { Suspense } from 'react'
import { getTweet } from 'react-tweet/api'
import { type TweetProps, TweetNotFound, TweetSkeleton } from 'react-tweet'
import { MyTweet } from './my-tweet'
 
const TweetContent = async ({ id, components, onError }: TweetProps) => {
  const tweet = id
    ? await getTweet(id).catch((err) => {
        if (onError) {
          onError(err)
        } else {
          console.error(err)
        }
      })
    : undefined
 
  if (!tweet) {
    const NotFound = components?.TweetNotFound || TweetNotFound
    return <NotFound />
  }
 
  return <MyTweet tweet={tweet} components={components} />
}
 
export const Tweet = ({
  fallback = <TweetSkeleton />,
  ...props
}: TweetProps) => (
  <Suspense fallback={fallback}>
    {/* @ts-ignore: Async components are valid in the app directory */}
    <TweetContent {...props} />
  </Suspense>
)

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 Next.js.

TweetContent is an async component that fetches the tweet and passes it to MyTweet. async only works for React Server Components (RSC) (opens in a new tab) so if your framework does not support RSC you can use SWR (opens in a new tab) instead:

tweet.tsx
'use client'
 
import {
  type TweetProps,
  EmbeddedTweet,
  TweetNotFound,
  TweetSkeleton,
  useTweet,
} from 'react-tweet'
 
export const Tweet = ({
  id,
  apiUrl,
  fallback = <TweetSkeleton />,
  components,
  onError,
}: TweetProps) => {
  const { data, error, isLoading } = useTweet(id, apiUrl)
 
  if (isLoading) return fallback
  if (error || !data) {
    const NotFound = components?.TweetNotFound || TweetNotFound
    return <NotFound error={onError ? onError(error) : error} />
  }
 
  return <EmbeddedTweet tweet={data} components={components} />
}