# Custom UI and Abstraxion loading states

This guide is about **your own buttons, copy, and loading states**—using **`useAbstraxionAccount`** (and optionally **`useAbstraxionSigningClient`**) with **`login()`**, not the legacy **`<Abstraxion />`** modal / **`@burnt-labs/ui`** bundle. It goes deeper on **granular loading flags** and **redirect return** handling than the [Account abstraction tutorial](https://docs.burnt.com/xion/developers/accounts/web-app/build-react-dapp-with-account-abstraxion) (which already uses the same hook-first connect pattern). It does **not** walk through choosing or comparing **`authentication.type`**; that belongs in the section hub.

**Live reference:** [xion.js `apps/demo-app` — `/loading-states`](https://github.com/burnt-labs/xion.js/tree/main/apps/demo-app/src/app/loading-states).

**Prerequisite:** You have already wrapped the app with **`AbstraxionProvider`** and set **`authentication`** (for dashboard Meta Account login, **`auto`** is the usual default). See [Web App Development](https://docs.burnt.com/xion/developers/accounts/web-app) for the mode glossary, env vars, and when to use **`signer`** or **embedded**—those topics are not repeated here. The **`login()`**, **`?granted=true`**, and flag patterns below apply to **dashboard-style** flows (`auto` / `popup` / `redirect`); for **`type: "signer"`**, start from [Abstraxion signer mode](https://docs.burnt.com/xion/developers/accounts/web-app/abstraxion-signer-mode).

Hook-level flags are **independent of whether you render a modal**: they describe session and navigation state from the SDK, not a specific widget.

## `useAbstraxionAccount` flags

Destructure the hook and drive your layout from granular booleans (wording aligned with the demo tooltips):

| Flag                      | Meaning                                                                                                                             |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| **`isInitializing`**      | Brief period after mount before the provider knows real connection state (avoid flashing “logged out” too early).                   |
| **`isConnecting`**        | User initiated login; active connection attempt in progress.                                                                        |
| **`isConnected`**         | Context resolved: user has an active session **or** you can treat as “ready to show app shell.”                                     |
| **`isDisconnected`**      | User explicitly logged out; blocks auto re-connect until they start login again.                                                    |
| **`isLoading`**           | Aggregated busy state: initializing, connecting, or transitional work—use for disabling primary actions / showing a single spinner. |
| **`isReturningFromAuth`** | User just came back from the auth app callback (e.g. redirect flow); optional dedicated “Finishing sign-in…” UI.                    |
| **`isLoggingIn`**         | Narrow window right after `login()` is invoked while the SDK starts the flow.                                                       |

**Session lifecycle (simplified):** mount → **`isInitializing`** → restored session or disconnected → user taps connect → **`isLoggingIn`** / **`isConnecting`** → popup closes or redirect returns (**`isReturningFromAuth`**) → **`isConnected`** with `data.bech32Address`.

Use **`isLoading`** when you want one gate for “disable submit / show full-page loader”; combine finer flags when you want different copy for “opening auth” vs “restoring session”.

## `login()` without the `<Abstraxion />` modal

Call **`login()`** from `useAbstraxionAccount` to start authentication without importing the pre-built modal component.

```typescript
const { data: account, login, logout, isConnecting, isLoading } =
  useAbstraxionAccount();
```

You do **not** need `@burnt-labs/abstraxion/dist/index.css` for hook-only UIs built with your own components.

## Optional: finishing login after redirect

With **`auto`** on desktop, auth often runs in a **popup** and the parent page stays mounted. With **full-page redirect** (typical mobile leg of **`auto`**, or explicit **`redirect`**), the user may return to your URL with **`?granted=true`**. Call **`login()`** once to finalize session restoration (the demo illustrates this). Popup-heavy flows hit this path less often.

```typescript
useEffect(() => {
  const searchParams = new URLSearchParams(window.location.search);
  if (searchParams.get("granted") === "true") {
    void login();
  }
}, [login]);
```

## Example: minimal custom UI

```typescript
import { useAbstraxionAccount, useAbstraxionSigningClient } from "@burnt-labs/abstraxion";

const btnClass =
  "w-full rounded-md border border-zinc-600 bg-zinc-900 px-4 py-2 text-white disabled:opacity-50";

export default function Page(): JSX.Element {
  const {
    data: account,
    login,
    logout,
    isLoading,
    isConnected,
  } = useAbstraxionAccount();
  const { client } = useAbstraxionSigningClient();

  if (isLoading && !isConnected) {
    return (
      <main className="flex min-h-screen items-center justify-center p-4">
        <p className="text-sm text-neutral-400">Preparing wallet session…</p>
      </main>
    );
  }

  return (
    <main className="m-auto flex min-h-screen max-w-xs flex-col items-center justify-center gap-4 p-4">
      <h1 className="text-2xl font-bold text-white">ABSTRAXION</h1>
      {account?.bech32Address ? (
        <>
          <p className="truncate text-xs text-neutral-400">{account.bech32Address}</p>
          {client ? <p className="text-xs text-green-400">Signing client ready</p> : null}
          <button type="button" className={btnClass} onClick={() => logout()}>
            LOGOUT
          </button>
        </>
      ) : (
        <button
          type="button"
          className={btnClass}
          disabled={isLoading}
          onClick={() => void login()}
        >
          CONNECT
        </button>
      )}
    </main>
  );
}
```

## Migrating from the legacy modal pattern

1. Remove **`<Abstraxion />`** if you still mount the old bundled modal.
2. Prefer **`login()`** (and **`logout()`**) with **native `<button>`** (or your design system) instead of Burnt UI primitives.
3. Replace a single “connecting” boolean with the **granular flags** above to avoid UI flicker and double-submits.

## Related

* [Web App Development — modes hub](https://docs.burnt.com/xion/developers/accounts/web-app)
* [Account abstraction with gasless transactions (hook-first tutorial)](https://docs.burnt.com/xion/developers/accounts/web-app/build-react-dapp-with-account-abstraxion)
* [Abstraxion signer mode](https://docs.burnt.com/xion/developers/accounts/web-app/abstraxion-signer-mode)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.burnt.com/xion/developers/accounts/web-app/custom-ui-abstraxion-authentication.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
