# 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. The
import map lets the headless examples use the bare `@unidy.io/sdk` specifier —
the same import a bundler/npm setup uses; drop the import map if you install the
package instead.

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

<u-config
  base-url="https://hannover96.staging.unidy.de"
  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>

      <!-- demo-motion:newsletters:start -->
      <div class="rounded-xl border border-border p-3">
        <label class="flex cursor-pointer items-center justify-between p-2">
          <span class="font-semibold">96-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="clubnews"
              checked="true"></u-newsletter-preference-checkbox>
            Clubnews
          </label>
          <label class="flex cursor-pointer items-center gap-3 text-sm">
            <u-newsletter-preference-checkbox
              internal-name="ns_with_prefs"
              preference-identifier="ticketnews"></u-newsletter-preference-checkbox>
            Ticketnews
          </label>
          <label class="flex cursor-pointer items-center gap-3 text-sm">
            <u-newsletter-preference-checkbox
              internal-name="ns_with_prefs"
              preference-identifier="fannews"></u-newsletter-preference-checkbox>
            Fannews
          </label>
          <label class="flex cursor-pointer items-center gap-3 text-sm">
            <u-newsletter-preference-checkbox
              internal-name="ns_with_prefs"
              preference-identifier="familynews"></u-newsletter-preference-checkbox>
            Familynews
          </label>
        </div>
        <u-error-message for="ns_with_prefs" class-name="text-danger text-sm"></u-error-message>
      </div>

      <!-- "Produktempfehlung" (ns_productrelated_with_prefs) is deliberately not
           offered here: it is opt-in-only and gets set elsewhere, e.g. at
           checkout. Members who already carry it can switch it off in the
           subscription center — see /subscription-center. -->
      <!-- demo-motion:newsletters:end -->

      <!-- 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">
      <!-- demo-motion:newsletters:start -->
      <div class="rounded-xl border border-border p-4">
        <div class="flex items-center justify-between">
          <span class="font-semibold">96-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>

        <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="clubnews"></u-newsletter-preference-checkbox>
              Clubnews
            </label>
            <label class="flex cursor-pointer items-center gap-3 text-sm">
              <u-newsletter-preference-checkbox
                internal-name="ns_with_prefs"
                preference-identifier="ticketnews"></u-newsletter-preference-checkbox>
              Ticketnews
            </label>
            <label class="flex cursor-pointer items-center gap-3 text-sm">
              <u-newsletter-preference-checkbox
                internal-name="ns_with_prefs"
                preference-identifier="fannews"></u-newsletter-preference-checkbox>
              Fannews
            </label>
            <label class="flex cursor-pointer items-center gap-3 text-sm">
              <u-newsletter-preference-checkbox
                internal-name="ns_with_prefs"
                preference-identifier="familynews"></u-newsletter-preference-checkbox>
              Familynews
            </label>
          </div>
        </div>
      </div>

      <!-- Produktempfehlung is opt-in-only: the card exists purely so members who
           already have it can turn it off. newsletter.subscribed keeps it out of
           the DOM for everyone else, and unsubscribing removes the subscription
           from the store — so the card disappears on the spot. This newsletter
           has no preferences, hence no checkboxes. -->
      <u-conditional-render when="newsletter.subscribed" is="ns_productrelated_with_prefs">
        <div class="rounded-xl border border-border p-4">
          <div class="flex items-center justify-between">
            <span class="font-semibold">Produktempfehlung</span>
            <u-newsletter-toggle-subscription-button
              internal-name="ns_productrelated_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>
        </div>
      </u-conditional-render>
      <!-- demo-motion:newsletters:end -->
    </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
