---
title: JavaScript SDK quickstart
---

# JavaScript SDK (`@littlexlittle/id`)

The SDK ships in two flavors:

1. **Hosted bundle** — `https://id.littlexlittle.org/sdk.js`, no build step.
2. **npm package** — `@littlexlittle/id`, tree-shakable ESM for SPAs.

Both expose the same `lxl.accounts.id.*` API. The hosted bundle exposes it as the global `lxl`; the npm package exports named functions.

## Install

=== "npm"

    ```bash
    npm install @littlexlittle/id
    ```

=== "yarn"

    ```bash
    yarn add @littlexlittle/id
    ```

=== "pnpm"

    ```bash
    pnpm add @littlexlittle/id
    ```

=== "Hosted (no install)"

    ```html
    <script src="https://id.littlexlittle.org/sdk.js" async defer></script>
    ```

## Initialize

```js
import { initialize, prompt, renderButton } from '@littlexlittle/id';

initialize({
  client_id: 'YOUR_CLIENT_ID',
  callback: handleCredential,
  auto_select: true,
  use_fedcm_for_prompt: true,  // browser-native dialog when supported
});

function handleCredential(response) {
  // response.credential = id_token (JWT)
  // response.select_by  = 'auto' | 'user' | 'one_tap'
  fetch('/auth/lxl', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ credential: response.credential }),
  });
}
```

## Render a button

```js
renderButton(document.getElementById('signin'), {
  type: 'standard',     // or 'icon'
  theme: 'outline',     // or 'filled_purple', 'filled_white'
  size: 'large',        // or 'medium' | 'small'
  text: 'signin_with',  // or 'signup_with' | 'continue_with' | 'signin'
  shape: 'rectangular', // or 'pill' | 'circle' | 'square'
  width: 320,
});
```

## Show the One-Tap prompt

```js
prompt((notification) => {
  if (notification.isNotDisplayed()) console.log('skipped:', notification.getNotDisplayedReason());
  if (notification.isSkippedMoment()) console.log('user dismissed');
});
```

## Code flow (PKCE) for SPAs that need server-side tokens

```js
import { oauth2 } from '@littlexlittle/id';

const codeClient = oauth2.initCodeClient({
  client_id: 'YOUR_CLIENT_ID',
  scope: 'openid profile email lxl.access',
  ux_mode: 'popup',
  callback: ({ code }) => {
    // Send code to your backend; backend exchanges for tokens.
    fetch('/auth/exchange', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ code }),
    });
  },
});

document.getElementById('signin').onclick = () => codeClient.requestCode();
```

## Public API

| Method | Purpose |
|---|---|
| `initialize(config)` | Configure client, callback, auto-select. |
| `prompt(notification?)` | Show One-Tap (FedCM where available). |
| `renderButton(el, options)` | Pre-rendered button. |
| `disableAutoSelect()` | Suppress silent sign-in for this user. |
| `cancel()` | Hide the prompt without dismissing it persistently. |
| `revoke(hint, done)` | Tell the IdP to forget consent for this client. |
| `oauth2.initCodeClient(config)` | PKCE code flow client. |
| `oauth2.initTokenClient(config)` | Implicit-style token flow (legacy). |

## Auto-init from HTML

The SDK scans the DOM at load for `[data-lxl-id]` and auto-initializes. Useful when you don't want to write any JS:

```html
<div data-lxl-id="CLIENT_ID"
     data-callback="onSignIn"
     data-auto_select="true"
     data-prompt_parent_id="signin-area"
     data-use_fedcm_for_prompt="true"
     data-itp_support="true"></div>
```

## Next

- [One-Tap deep dive](../guides/one-tap.md)
- [Silent sign-in](../guides/silent-signin.md)
- [PKCE explained](../guides/pkce.md)
