lens-blocks
componentaccount-list-itemsource: ok · hit
Lens Account List Item
A list item for a Lens account displaying the avatar, name, and handle.
npx shadcn add "https://lensblocks.com/r/account-list-item.json"free
No selection tags yet — empty means no evidence, not lack of support.
Dependencies
Bundle weight · lighticonslucide-react
Registry dependencies
avatarbuttonskeletonhttps://lensblocks.com/r/utils.json
Files2 · source cached 10/9/2026, 9:24:11 AM
registry/new-york/components/account/lens-account-list-item.tsx
"use client";
import { Account, AuthenticatedUser } from "@lens-protocol/react";
import { Avatar, AvatarFallback, AvatarImage } from "@/registry/new-york/ui/avatar";
import { CheckCircle2Icon, ChevronRight, Loader, UserCircle2 } from "lucide-react";
import { truncateAddress } from "@/registry/new-york/lib/lens-utils";
import { ReactNode } from "react";
import { isResult, Result } from "@/registry/new-york/lib/result";
import { LensAccountListItemSkeleton } from "@/registry/new-york/components/account/lens-account-list-item-skeleton";
type LensAccountListItemProps = {
account: Account | Result<Account>;
selectedAccount?: Account | null;
onAccountSelected?: (account: Account) => void;
authenticatedUser?: AuthenticatedUser | null;
showChevron?: boolean;
renderDivider?: () => ReactNode;
};
export const LensAccountListItem = ({
account: accountRes,
selectedAccount,
onAccountSelected,
authenticatedUser,
showChevron = true,
renderDivider,
}: LensAccountListItemProps) => {
const isAccountResult = isResult(accountRes);
const account = isAccountResult ? accountRes.data : accountRes;
const isAuthenticated =
authenticatedUser && authenticatedUser?.address.toLowerCase() === account?.address.toLowerCase();
const isSelected = (onAccountSelected && isAuthenticated) ?? false;
const Divider = renderDivider;
if (isAccountResult && accountRes.error) {
return null; // show error state
}
if (!account || (isAccountResult && accountRes.loading)) {
return (
<div className="w-full flex items-center text-start">
<LensAccountListItemSkeleton showChevron={showChevron} />
</div>
);
}
return (
<div>
<button
type="button"
disabled={selectedAccount?.address !== undefined || isSelected}
onClick={() => onAccountSelected?.(account)}
className={`w-full flex items-center text-start p-2 gap-2 enabled:cursor-pointer enabled:hover:bg-neutral-100 enabled:focus:bg-neutral-100 focus:outline-0 rounded-sm ${isSelected ? "border" : "disabled:opacity-45"}`}
>
<Avatar className="flex-none w-10 h-10">
<AvatarImage src={account.metadata?.picture} alt="Account avatar" />
<AvatarFallback>
<UserCircle2 className="w-10 h-10 opacity-45" />
</AvatarFallback>
</Avatar>
<div className="flex-grow flex flex-col w-full min-w-0">
<div className="flex gap-1 items-center">
<span className="text-sm font-semibold">
{account.metadata?.name ?? account.username?.localName ?? "[anonymous]"}
</span>
</div>
<span className="text-xs opacity-65 truncate">
{account.metadata?.name ? "@" + account.username?.localName : truncateAddress(account.address)}
</span>
</div>
{selectedAccount?.address == account.address ? (
<Loader className="animate-spin flex-none opacity-45 w-4 h-4" />
) : showChevron && isSelected ? (
<CheckCircle2Icon className="flex-none opacity-45 w-4 h-4 text-accent-foreground" />
) : (
showChevron && <ChevronRight className="flex-none opacity-45 w-4 h-4" />
)}
</button>
{Divider && <Divider />}
</div>
);
};
registry/new-york/components/account/lens-account-list-item-skeleton.tsx
import { Skeleton } from "@/registry/new-york/ui/skeleton";
export const LensAccountListItemSkeleton = ({ showChevron = true }: { showChevron?: boolean }) => {
return (
<div className="w-full flex items-center space-x-2 p-2">
<Skeleton className="h-10 w-10 rounded-full flex-none" />
<div className="flex-grow space-y-1.5">
<Skeleton className="h-4 w-9/12" />
<Skeleton className="h-3 w-5/12" />
</div>
{showChevron && <Skeleton className="w-4 h-4" />}
</div>
);
};