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>.
View this guide as MarkdownSubscribe 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
<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">
{t('Déjà abonné ? Gérer vos abonnements', '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">{t('Choisir la newsletter', 'Select newsletter')}</p>
<!-- Newsletter without preferences -->
<div class="rounded-xl border border-border p-3">
<label class="flex cursor-pointer items-center justify-between p-2">
<span class="font-semibold">{t('Newsletter du LS', 'LS Newsletter')}</span>
<u-newsletter-checkbox
internal-name="main_lausanne"
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>
<u-error-message for="main_lausanne" 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>
{t("J'accepte de recevoir la newsletter sélectionnée et la politique de confidentialité.", 'I agree to receive the selected newsletter 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">
{t("S'abonner", '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">
{t('Vous êtes identifié — gérez votre abonnement ci-dessous.', 'You are identified for newsletter management — see the section below.')}
</p>
</u-conditional-render>
</u-newsletter-root> Choisir la newsletter
Vous êtes identifié — gérez votre abonnement ci-dessous.
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
<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={t("Utiliser une autre adresse e-mail", "Use a different email")}>
✕
</u-newsletter-logout-button>
</u-email-field>
</div>
<div class="flex flex-col gap-4">
<!-- Newsletter without preferences -->
<div class="rounded-xl border border-border p-4">
<div class="flex items-center justify-between">
<span class="font-semibold">{t('Newsletter du LS', 'LS Newsletter')}</span>
<u-newsletter-toggle-subscription-button
internal-name="main_lausanne"
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="main_lausanne">
<u-conditional-render when="newsletter.confirmed" is="main_lausanne" 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>{t('Veuillez confirmer votre abonnement — nous vous avons envoyé un e-mail.', 'Please confirm your subscription — we sent you an email.')}</span>
<u-newsletter-resend-doi-button
internal-name="main_lausanne"
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">
{t("Pas encore identifié — abonnez-vous ci-dessus, connectez-vous ou ouvrez le lien d'un e-mail de newsletter.", "Not identified yet — subscribe above, sign in, or open the link from a newsletter email.")}
</p>
</u-conditional-render>
</u-newsletter-root> Pas encore identifié — abonnez-vous ci-dessus, connectez-vous ou ouvrez le lien d'un e-mail de newsletter.