Abstract Sign In
Sign in with account abstraction using Abstract global wallet
AbstractAuthentication
Sign in with Abstract
Supports
Technologies
Installation
Install Web3 dependencies
npm install @abstract-foundation/agw-react wagmi viem@2.x @tanstack/react-query
This component uses the Abstract global wallet for web3 wallet connectivity which requires additional configurations to your project. To ensure it works properly follow the Install Abstract Global Wallet setup guide.
Add Shadcn components
npx shadcn@latest add button
This component uses the Shadcn component library which requires additional configurations to your project. To ensure it works properly follow the Install Shadcn UI setup guide.
Add utils file
Create a file named
lib/utils.ts
and add the following code:import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
Copy and paste source code
"use client";
import { useLoginWithAbstract } from "@abstract-foundation/agw-react";
import { useAccount } from "wagmi";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { useId } from "react";
const AbstractSignIn = () => {
const { login, logout } = useLoginWithAbstract();
const { address, isConnected, isConnecting, isReconnecting } = useAccount();
return (
<div className="flex flex-col items-center justify-center min-h-screen font-mono px-4 md:px-8">
{/* loading state */}
{(isConnecting || isReconnecting) && (
<div className="h-screen w-full absolute inset-0 bg-white/5 backdrop-blur-sm z-10 flex justify-center items-center pointer-events-none">
<div className="w-8 h-8 border-[4px] border-[#02CA6A] border-b-transparent rounded-full inline-block box-border animate-spin" />
</div>
)}
{/* right corner gradient blob */}
<div className="absolute inset-0 -z-10 mx-0 max-w-none overflow-hidden">
<div
className="absolute
right-[-320px] top-[-280px] rotate-[42deg] h-[30rem] w-[88.25rem]
md:right-[-220px] md:top-[-180px] md:rotate-[22deg] md:h-[25rem] md:w-[88.25rem]
lg:right-[-180px] lg:top-[-160px] lg:rotate-[18deg] lg:h-[25rem] lg:w-[88.25rem]
2xl:right-[-180px] 2xl:top-[-150px] 2xl:rotate-[18deg] 2xl:h-[35rem] 2xl:w-[88.25rem]"
>
<div className="absolute inset-0 bg-[#02CA6A] opacity-20 [mask-image:radial-gradient(farthest-side_at_top,white,transparent)] "></div>
</div>
</div>
{/* grid pattern */}
<Grid
width={40}
height={40}
x={-1}
y={-1}
className={cn(
"absolute top-0 right-0 w-full h-[50%]",
"[mask-image:linear-gradient(to_bottom_left,white,transparent,transparent)]"
)}
/>
{/* content */}
<div className="flex flex-col items-center justify-center gap-10 max-w-[500px]">
<Logo className="w-14 h-14" />
{isConnected && address ? (
<div className="flex flex-col items-center justify-center gap-6">
<p className=" whitespace-pre-wrap text-center text-3xl font-medium tracking-tighter text-white">
Now it's time to build something cool here!
</p>
<Button
onClick={logout}
className="w-full md:w-[347px] rounded-[8px] bg-white hover:bg-[#02CA6A]/70 hover:text-white text-black font-bold text-lg"
>
Logout
</Button>
</div>
) : (
<div className="flex flex-col items-center justify-center gap-6">
<p className=" whitespace-pre-wrap text-center text-3xl font-medium tracking-tighter text-white">
Sign in with Abstract
</p>
<Button
onClick={login}
className="w-full md:w-[347px] rounded-[8px] bg-[#02CA6A]/80 hover:bg-[#02CA6A]/70 text-white font-bold text-lg"
>
Sign in
</Button>
</div>
)}
</div>
<div className="h-[0.5px] bg-white/30 w-full md:w-[347px] mt-8 mb-2" />
<div className="flex justify-between w-full md:w-[347px]">
<p className="text-white/50 text-sm">Supports</p>
<div className="flex items-center gap-2">
<GmailLogo className="w-4 h-4" />
<EmailLogo className="w-4 h-4" />
<WalletLogo className="w-4 h-4" />
</div>
</div>
</div>
);
};
export default AbstractSignIn;
interface GridPatternProps {
width?: number;
height?: number;
x?: number;
y?: number;
squares?: Array<[x: number, y: number]>;
strokeDasharray?: string;
className?: string;
[key: string]: unknown;
}
const Grid = ({
width = 40,
height = 40,
x = -1,
y = -1,
strokeDasharray = "0",
squares,
className,
...props
}: GridPatternProps) => {
const id = useId();
return (
<svg
aria-hidden="true"
className={cn(
"pointer-events-none absolute inset-0 h-full w-full fill-gray-400/20 stroke-gray-400/20",
className
)}
{...props}
>
<defs>
<pattern
id={id}
width={width}
height={height}
patternUnits="userSpaceOnUse"
x={x}
y={y}
>
<path
d={`M.5 ${height}V.5H${width}`}
fill="none"
strokeDasharray={strokeDasharray}
/>
</pattern>
</defs>
<rect width="100%" height="100%" strokeWidth={0} fill={`url(#${id})`} />
{squares && (
<svg x={x} y={y} className="overflow-visible">
{squares.map(([x, y]) => (
<rect
strokeWidth="0"
key={`${x}-${y}`}
width={width - 1}
height={height - 1}
x={x * width + 1}
y={y * height + 1}
/>
))}
</svg>
)}
</svg>
);
};
const Logo: React.FC<React.SVGProps<SVGSVGElement>> = (props) => {
return (
<svg
width="28"
height="25"
viewBox="0 0 28 25"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M23.5006 22.2831L18.0126 16.9277H9.34632L3.85828 22.2831L6.43334 24.7959L11.9214 19.4405C12.3919 18.9814 13.0122 18.7309 13.6795 18.7309C14.3468 18.7309 14.967 18.9814 15.4375 19.4405L20.9256 24.7959L23.5006 22.2831Z"
fill="#02CA6A"
/>
<path
d="M18.928 15.3833L26.4221 17.341L27.3632 13.9057L19.869 11.948C19.2274 11.7811 18.6927 11.3804 18.359 10.8169C18.0254 10.2575 17.9399 9.6022 18.111 8.9761L20.1171 1.66308L16.5967 0.744781L14.5906 8.05779L18.9237 15.3792L18.928 15.3833Z"
fill="#02CA6A"
/>
<path
d="M0.941051 17.341L8.43524 15.3833L8.43952 15.3792L12.7726 8.05779L10.7665 0.744781L7.24609 1.66308L9.25224 8.9761C9.42334 9.6022 9.33779 10.2575 9.00415 10.8169C8.6705 11.3804 8.13582 11.7811 7.49419 11.948L0 13.9057L0.941051 17.341Z"
fill="#02CA6A"
/>
</svg>
);
};
const GmailLogo: React.FC<React.SVGProps<SVGSVGElement>> = (props) => {
return (
<svg
width="512"
height="512"
viewBox="0 0 512 512"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M435.2 0H76.8C34.3845 0 0 34.3845 0 76.8V435.2C0 477.615 34.3845 512 76.8 512H435.2C477.615 512 512 477.615 512 435.2V76.8C512 34.3845 477.615 0 435.2 0Z"
fill="white"
/>
<path d="M158 391V249L76 186V361C76 381 86 391 106 391" fill="#4285F4" />
<path d="M154 248L256 325L358 248V150L256 227L154 150" fill="#EA4335" />
<path
d="M354 391V249L436 186V361C436 381 426 391 406 391"
fill="#34A853"
/>
<path
d="M76 188L158 251V153L128 130C101 109 76 130 76 156"
fill="#C5221F"
/>
<path
d="M436 188L354 251V153L384 130C411 109 436 130 436 156"
fill="#FBBC04"
/>
</svg>
);
};
const EmailLogo: React.FC<React.SVGProps<SVGSVGElement>> = (props) => {
return (
<svg
width="512"
height="512"
viewBox="0 0 512 512"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<rect width="512" height="512" rx="77" fill="white" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M91.0417 121L76 136.056V376.944L91.0417 392H421.958L437 376.944V136.056L421.958 121H91.0417ZM106.083 170.091V361.889H406.917V170.086L256.498 306.958L106.083 170.091ZM383.049 151.111H129.947L256.498 266.264L383.049 151.111Z"
fill="#080341"
/>
</svg>
);
};
const WalletLogo: React.FC<React.SVGProps<SVGSVGElement>> = (props) => {
return (
<svg
width="512"
height="512"
viewBox="0 0 512 512"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<rect width="512" height="512" rx="77" fill="white" />
<path
d="M342 199.25V187.8C342 171.769 342 163.753 338.875 157.63C336.128 152.243 331.742 147.864 326.348 145.12C320.216 142 312.188 142 296.133 142H172.867C156.812 142 148.784 142 142.652 145.12C137.258 147.864 132.873 152.243 130.125 157.63C127 163.753 127 171.769 127 187.8V199.25M127 199.25V325.2C127 341.231 127 349.248 130.125 355.371C132.873 360.757 137.258 365.136 142.652 367.88C148.784 371 156.812 371 172.867 371H339.133C355.188 371 363.216 371 369.348 367.88C374.742 365.136 379.128 360.757 381.875 355.371C385 349.248 385 341.231 385 325.2V245.05C385 229.019 385 221.003 381.875 214.88C379.128 209.493 374.742 205.114 369.348 202.37C363.216 199.25 355.188 199.25 339.133 199.25H127ZM385 256.5H356.333C340.501 256.5 327.667 269.315 327.667 285.125C327.667 300.935 340.501 313.75 356.333 313.75H385"
stroke="black"
stroke-width="30"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
);
};
"One of the only full-stack Web3 component libraries i've seen in the space so far. Ten out of ten recommended. Saved me a ton of time. Can't wait to see what templates they release next."
Samy
Side projects builder