Advanced
Customizing the theme components
The components used by the X theme allow some simple customization options for common use cases. However you can also have full control over the xeet by building your own Xeet
component with the components and features of the theme that you would like to use.
For example, you can build your own xeet component but without the reply button like so:
import type { Xeet } from 'react-xeet/api'
import {
type XComponents,
XeetContainer,
XeetHeader,
XeetInReplyTo,
XeetBody,
XeetMedia,
XeetInfo,
XeetActions,
enrichXeet,
} from 'react-xeet'
type Props = {
xeet: Xeet
components?: XComponents
}
export const MyXeet = ({ xeet: t, components }: Props) => {
const xeet = enrichXeet(t)
return (
<XeetContainer>
<XeetHeader xeet={xeet} components={components} />
{xeet.in_reply_to_status_id_str && <XeetInReplyTo xeet={xeet} />}
<XeetBody xeet={xeet} />
{xeet.mediaDetails?.length ? (
<XeetMedia xeet={xeet} components={components} />
) : null}
<XeetInfo xeet={xeet} />
<XeetActions xeet={xeet} />
{/* We're not including the `XeetReplies` component that adds the reply button */}
</XeetContainer>
)
}
Then, you can build your own Xeet
component that uses the MyXeet
component:
import { Suspense } from 'react'
import { getXeet } from 'react-xeet/api'
import { type XeetProps, XeetNotFound, XeetSkeleton } from 'react-xeet'
import { MyXeet } from './my-xeet'
const XeetContent = async ({ id, components, onError }: XeetProps) => {
const xeet = id
? await getXeet(id).catch((err) => {
if (onError) {
onError(err)
} else {
console.error(err)
}
})
: undefined
if (!xeet) {
const NotFound = components?.XeetNotFound || XeetNotFound
return <NotFound />
}
return <MyXeet xeet={xeet} components={components} />
}
export const Xeet = ({
fallback = <XeetSkeleton />,
...props
}: XeetProps) => (
<Suspense fallback={fallback}>
{/* @ts-ignore: Async components are valid in the app directory */}
<XeetContent {...props} />
</Suspense>
)
The Xeet
component uses Suspense
to progressively load the xeet (non-blocking rendering) and to opt-in into streaming if your framework supports it, like Next.js.
XeetContent
is an async component that fetches the xeet and passes it to MyXeet
. 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:
'use client'
import {
type XeetProps,
EmbeddedXeet,
XeetNotFound,
XeetSkeleton,
useXeet,
} from 'react-xeet'
export const Xeet = ({
id,
apiUrl,
fallback = <XeetSkeleton />,
components,
onError,
}: XeetProps) => {
const { data, error, isLoading } = useXeet(id, apiUrl)
if (isLoading) return fallback
if (error || !data) {
const NotFound = components?.XeetNotFound || XeetNotFound
return <NotFound error={onError ? onError(error) : error} />
}
return <EmbeddedXeet xeet={data} components={components} />
}