> ## Documentation Index
> Fetch the complete documentation index at: https://developers.tally.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Popups

> Open and close Tally forms as popups from your own JavaScript.

Popups let you open a Tally form in a modal when you need it — on a button click, after a
delay, when a user is about to leave the page, or any other moment that fits your product.
You drive them entirely from your own JavaScript via the `window.Tally` object.

## Add the widget script

Include the Tally widget script once on any page that uses popups:

```html theme={null}
<script src="https://tally.so/widgets/embed.js"></script>
```

Both methods below require the **Form ID**, which you can find in the URL of your form:

```
https://tally.so/r/[FORM_ID]
https://tally.so/embed/[FORM_ID]
https://tally.so/forms/[FORM_ID]/edit
```

## Tally.openPopup()

Opens a form in a popup.

```javascript theme={null}
// Example
Tally.openPopup('mRoDv3', { layout: 'modal' });
```

### Reference

```typescript theme={null}
openPopup: (
  formId: string,
  options?: {
    // Unique identifier used by "Show only once" and "Don't show after submit"
    key?: string;
    layout?: 'default' | 'modal';
    width?: number;
    alignLeft?: boolean;
    hideTitle?: boolean;
    overlay?: boolean;
    emoji?: {
      text: string;
      animation:
        | 'none'
        | 'wave'
        | 'tada'
        | 'heart-beat'
        | 'spin'
        | 'flash'
        | 'bounce'
        | 'rubber-band'
        | 'head-shake';
    };
    autoClose?: number; // in milliseconds
    showOnce?: boolean;
    doNotShowAfterSubmit?: boolean;
    // Load the form via its custom domain URL instead of tally.so
    customFormUrl?: string;
    hiddenFields?: {
      [key: string]: any;
    };
    onOpen?: () => void;
    onClose?: () => void;
    onPageView?: (page: number) => void;
    onSubmit?: (payload: SubmissionPayload) => void;
  },
) => void;
```

## Tally.closePopup()

Closes a previously opened popup.

```javascript theme={null}
// Example
Tally.closePopup('mRoDv3');
```

### Reference

```typescript theme={null}
closePopup: (formId: string) => void;
```

## Save page URL and query parameters

The widget automatically forwards the host page's path and query parameters to the popup.
To capture them in your submissions, add matching [hidden fields](https://tally.so/help/hidden-fields)
to your form.

For example, given the page URL:

```
https://company.com/register?ref=downloads&email=alice@example.com
```

Hidden fields named `originPage`, `ref`, and `email` will receive the following values:

| Hidden field | Value                                         |
| ------------ | --------------------------------------------- |
| originPage   | /register                                     |
| ref          | downloads                                     |
| email        | [alice@example.com](mailto:alice@example.com) |

## Events

Popups emit the same JavaScript events as embeds — plus a `Tally.PopupClosed` event when
the popup is dismissed. See [Events](/widgets/events) for the full payload reference. You
can also subscribe to popup-specific callbacks (`onOpen`, `onClose`, `onPageView`,
`onSubmit`) directly via the `options` argument of `Tally.openPopup()`.
