# Unidy Web SDK — Newsletter

Newsletter subscriptions work with or without an account: anonymous visitors subscribe with just an email (double opt-in), while identified users manage subscriptions and preferences in place. All state handling — has the visitor entered an email, are they subscribed, is the subscription confirmed — is exposed through <u-conditional-render>.

## Setup

Every example below assumes the SDK is loaded and configured once per page:

```html
<script type="module" src="https://cdn.jsdelivr.net/npm/@unidy.io/sdk@1.8.1/dist/sdk/sdk.esm.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@unidy.io/sdk@1.8.1/dist/sdk/sdk.css">

<u-config
  base-url="https://hammarby.staging.unidy.app"
  api-key="your-api-key"
  locale="en"
  check-signed-in="true"></u-config>
```

## Subscribe form

An anonymous subscribe widget: email field, one checkbox per newsletter with nested topic preferences, an explicit consent checkbox, and a submit button. After subscribing, the double-opt-in email is sent automatically. The 'already subscribed' link uses for="login" to switch into management mode instead.

- **Works logged-out** — email is enough; no account required
- **Newsletter + preference checkboxes** — per-newsletter topics via preference-identifier
- **Consent checkbox** — u-newsletter-consent-checkbox stores explicit consent
- **State-driven UI** — u-conditional-render on newsletter.loggedIn / hasEmail

```html
<u-newsletter-root>
  <!-- Shown until the visitor identifies themselves (subscribes or logs in) -->
  <u-conditional-render when="newsletter.loggedIn" not>
    <u-email-field class-name="px-4 py-2 border border-border rounded-lg w-full"></u-email-field>
    <u-error-message for="email" class-name="text-danger text-sm"></u-error-message>

    <!-- Offered once an email is typed: jump to subscription management instead -->
    <u-conditional-render when="newsletter.hasEmail">
      <u-submit-button
        for="login"
        class-name="mt-2 text-sm font-medium text-primary hover:underline cursor-pointer">
        Already subscribed? Manage your subscriptions
      </u-submit-button>
    </u-conditional-render>

    <div class="mt-4 flex flex-col gap-3">
      <p class="text-sm font-medium text-text-light">Select newsletters</p>

      <div class="rounded-xl border border-border p-3">
        <label class="flex cursor-pointer items-center justify-between p-2">
          <span class="font-semibold">Hammarby Newsletter</span>
          <u-newsletter-checkbox
            internal-name="ns_with_prefs"
            checked="true"
            class-name="appearance-none relative w-11 h-6 bg-border rounded-full cursor-pointer transition-colors checked:bg-primary after:content-[\'\'] after:absolute after:top-0.5 after:left-0.5 after:w-5 after:h-5 after:bg-white after:rounded-full after:shadow after:transition-transform checked:after:translate-x-5"
          ></u-newsletter-checkbox>
        </label>
        <div class="ml-2 mt-1 flex flex-col gap-2">
          <label class="flex cursor-pointer items-center gap-3 text-sm">
            <u-newsletter-preference-checkbox
              internal-name="ns_with_prefs"
              preference-identifier="club_news_pref"
              checked="true"></u-newsletter-preference-checkbox>
            Club News
          </label>
          <label class="flex cursor-pointer items-center gap-3 text-sm">
            <u-newsletter-preference-checkbox
              internal-name="ns_with_prefs"
              preference-identifier="player_news_pref"
              checked="true"></u-newsletter-preference-checkbox>
            Player News
          </label>
          <label class="flex cursor-pointer items-center gap-3 text-sm">
            <u-newsletter-preference-checkbox
              internal-name="ns_with_prefs"
              preference-identifier="random_news_pref"></u-newsletter-preference-checkbox>
            Other News
          </label>
        </div>
        <u-error-message for="ns_with_prefs" class-name="text-danger text-sm"></u-error-message>
      </div>

      <div class="rounded-xl border border-border p-3">
        <label class="flex cursor-pointer items-center justify-between p-2">
          <span class="font-semibold">General Updates</span>
          <u-newsletter-checkbox
            internal-name="ns_without_prefs"
            class-name="appearance-none relative w-11 h-6 bg-border rounded-full cursor-pointer transition-colors checked:bg-primary after:content-[\'\'] after:absolute after:top-0.5 after:left-0.5 after:w-5 after:h-5 after:bg-white after:rounded-full after:shadow after:transition-transform checked:after:translate-x-5"
          ></u-newsletter-checkbox>
        </label>
        <u-error-message for="ns_without_prefs" class-name="text-danger text-sm"></u-error-message>
      </div>

      <!-- Explicit consent, stored with the subscription -->
      <label class="flex cursor-pointer items-start gap-3 text-sm text-text-light">
        <u-newsletter-consent-checkbox class-name="mt-0.5"></u-newsletter-consent-checkbox>
        I agree to receive the selected newsletters and accept the privacy policy.
      </label>

      <u-submit-button
        class-name="w-full bg-accent hover:bg-accent-hover text-white font-semibold py-2.5 rounded-lg transition cursor-pointer mt-2">
        Subscribe
      </u-submit-button>
      <u-error-message for="general" class-name="text-danger text-sm"></u-error-message>
    </div>
  </u-conditional-render>

  <u-conditional-render when="newsletter.loggedIn">
    <p class="text-success-text">
      You are identified for newsletter management — see the preference center below.
    </p>
  </u-conditional-render>
</u-newsletter-root>
```

Live demo: /newsletter#subscribe

## Preference center

Subscription management for an identified visitor: toggle subscriptions, resend the double-opt-in email while unconfirmed, and edit topic preferences that save on change. Visitors are identified by account sign-in, by subscribing, or by the preference token in newsletter email links — u-newsletter-logout-button switches to a different email.

- **Toggle subscriptions** — u-newsletter-toggle-subscription-button with per-state styling
- **Double opt-in handling** — newsletter.confirmed state + resend-DOI button
- **Preference token flow** — email links identify the visitor without a password
- **Switch email** — u-newsletter-logout-button clears the newsletter session

```html
<u-newsletter-root>
  <u-conditional-render when="newsletter.loggedIn">
    <!-- The identified email, with a "switch email" logout button -->
    <div class="relative mb-6">
      <u-email-field
        class-name="px-4 py-2 pr-10 border border-border rounded-lg w-full bg-background-light"
        disabled>
        <u-newsletter-logout-button
          class="absolute right-3 top-1/2 -translate-y-1/2 z-10"
          class-name="flex items-center justify-center w-6 h-6 rounded-full cursor-pointer text-text-muted hover:bg-background-muted hover:text-text"
          title="Use a different email">
          ✕
        </u-newsletter-logout-button>
      </u-email-field>
    </div>

    <div class="flex flex-col gap-4">
      <div class="rounded-xl border border-border p-4">
        <div class="flex items-center justify-between">
          <span class="font-semibold">Hammarby Newsletter</span>
          <u-newsletter-toggle-subscription-button
            internal-name="ns_with_prefs"
            class-name="text-sm font-medium rounded-lg px-3 py-1 cursor-pointer"
            subscribe-class-name="text-white bg-accent hover:bg-accent-hover"
            unsubscribe-class-name="text-danger border border-error-border hover:bg-error-bg"
          ></u-newsletter-toggle-subscription-button>
        </div>

        <!-- Double opt-in: subscribed but not yet confirmed -->
        <u-conditional-render when="newsletter.subscribed" is="ns_with_prefs">
          <u-conditional-render when="newsletter.confirmed" is="ns_with_prefs" not>
            <div
              class="mt-3 flex items-center justify-between gap-3 rounded-lg bg-warning-bg px-4 py-3 text-sm text-warning-text">
              <span>Please confirm your subscription — we sent you an email.</span>
              <u-newsletter-resend-doi-button
                internal-name="ns_with_prefs"
                class-name="whitespace-nowrap rounded-lg border border-warning-border px-3 py-1 text-sm font-medium cursor-pointer hover:bg-warning-border/40"
              ></u-newsletter-resend-doi-button>
            </div>
          </u-conditional-render>
        </u-conditional-render>

        <div class="mt-4 border-t border-border pt-4">
          <p class="mb-3 text-sm font-medium text-text-light">Preferences</p>
          <div class="flex flex-col gap-2">
            <label class="flex cursor-pointer items-center gap-3 text-sm">
              <u-newsletter-preference-checkbox
                internal-name="ns_with_prefs"
                preference-identifier="club_news_pref"></u-newsletter-preference-checkbox>
              Club News
            </label>
            <label class="flex cursor-pointer items-center gap-3 text-sm">
              <u-newsletter-preference-checkbox
                internal-name="ns_with_prefs"
                preference-identifier="player_news_pref"></u-newsletter-preference-checkbox>
              Player News
            </label>
            <label class="flex cursor-pointer items-center gap-3 text-sm">
              <u-newsletter-preference-checkbox
                internal-name="ns_with_prefs"
                preference-identifier="random_news_pref"></u-newsletter-preference-checkbox>
              Other News
            </label>
          </div>
        </div>
      </div>

      <div class="rounded-xl border border-border p-4">
        <div class="flex items-center justify-between">
          <span class="font-semibold">General Updates</span>
          <u-newsletter-toggle-subscription-button
            internal-name="ns_without_prefs"
            class-name="text-sm font-medium rounded-lg px-3 py-1 cursor-pointer"
            subscribe-class-name="text-white bg-accent hover:bg-accent-hover"
            unsubscribe-class-name="text-danger border border-error-border hover:bg-error-bg"
          ></u-newsletter-toggle-subscription-button>
        </div>

        <u-conditional-render when="newsletter.subscribed" is="ns_without_prefs">
          <u-conditional-render when="newsletter.confirmed" is="ns_without_prefs" not>
            <div
              class="mt-3 flex items-center justify-between gap-3 rounded-lg bg-warning-bg px-4 py-3 text-sm text-warning-text">
              <span>Please confirm your subscription — we sent you an email.</span>
              <u-newsletter-resend-doi-button
                internal-name="ns_without_prefs"
                class-name="whitespace-nowrap rounded-lg border border-warning-border px-3 py-1 text-sm font-medium cursor-pointer hover:bg-warning-border/40"
              ></u-newsletter-resend-doi-button>
            </div>
          </u-conditional-render>
        </u-conditional-render>
      </div>
    </div>
  </u-conditional-render>

  <u-conditional-render when="newsletter.loggedIn" not>
    <p class="text-text-light">
      Not identified yet — subscribe above, sign in, or open the link from a newsletter email (the
      preference token in the URL identifies you without a full account login).
    </p>
  </u-conditional-render>
</u-newsletter-root>
```

Live demo: /newsletter#preference-center

## Further reading

- Full component reference: https://github.com/UnidyID/unidy-sdk/blob/HEAD/packages/sdk/readme.md
- Official quick-start examples: https://github.com/UnidyID/unidy-sdk/blob/HEAD/packages/sdk/quick-start-examples.md
- Package: https://www.npmjs.com/package/@unidy.io/sdk
- All guides: /llms.txt
