atproto-ui Demo

A component library for rendering common AT Protocol records for applications such as Bluesky and Tangled.


Enter a handle to fetch your profile, latest Bluesky post, a Tangled string, and a Leaflet document.

Code Examples

Wrap your app with the provider once and drop the ready-made components wherever you need them.

import { AtProtoProvider, BlueskyPost } from 'atproto-ui';

export function App() {
    return (
        <AtProtoProvider>
            <BlueskyPost did="did:plc:example" rkey="3k2aexample" />
        </AtProtoProvider>
    );
}

Pass prefetched data to components to skip API calls—perfect for SSR or caching.

import { BlueskyPost, useLatestRecord } from 'atproto-ui';
import type { FeedPostRecord } from 'atproto-ui';

const LatestPostWithPrefetch: React.FC<{ did: string }> = ({ did }) => {
    // Fetch once with the hook
    const { record, rkey, loading } = useLatestRecord<FeedPostRecord>(
        did,
        'app.bsky.feed.post'
    );

    if (loading) return <span>Loading…</span>;
    if (!record || !rkey) return <span>No posts yet.</span>;

    // Pass prefetched record—BlueskyPost won't re-fetch it
    return <BlueskyPost did={did} rkey={rkey} record={record} />;
};

Use atcute directly to construct records and pass them to components—fully compatible!

import { Client, simpleFetchHandler, ok } from '@atcute/client';
import type { AppBskyFeedPost } from '@atcute/bluesky';
import { BlueskyPost } from 'atproto-ui';

// Create atcute client
const client = new Client({
    handler: simpleFetchHandler({ service: 'https://public.api.bsky.app' })
});

// Fetch a record
const data = await ok(
    client.get('com.atproto.repo.getRecord', {
        params: {
            repo: 'did:plc:ttdrpj45ibqunmfhdsb4zdwq',
            collection: 'app.bsky.feed.post',
            rkey: '3m45rq4sjes2h'
        }
    })
);

const record = data.value as AppBskyFeedPost.Main;

// Pass atcute record directly to component!
<BlueskyPost
    did="did:plc:ttdrpj45ibqunmfhdsb4zdwq"
    rkey="3m45rq4sjes2h"
    record={record}
/>