Skip to main content

Donor Landing Page

Donor Landing Page

Component Files: src/features/donors/components/DonorLandingPage.tsx (layout + form), src/features/donors/components/DonorLandingEmbeddedCheckout.tsx (lazy Stripe checkout) Route: Public URL (see URL Structure below) Access Level: Public (No authentication required) Last Updated: April 13, 2026 Status: ✅ Implemented

Recent Updates (April 13, 2026)

Giving-page security hardening

  • Strict org slug resolution: get-public-donation-page and client fallback lookup no longer fall back to "first match" when duplicate page slugs exist across organizations. If org_slug is missing/ambiguous/mismatched, the request fails instead of rendering the wrong organization's giving page.
  • Success route detection tightened: public donation success detection now accepts only known success route shapes (canonical and legacy), preventing normal pages whose slug happens to be success from being misclassified as receipt pages.
  • Reserved slug expanded: Donor Page Builder now blocks success as a slug to avoid collisions with dedicated success routes.
  • Open redirect mitigation: return_url is sanitized against an allowlist before navigation. Unsafe values are ignored.
  • Public receipt privacy: get-donation-details now requires session_id for public/anon requests and redacts donor identity fields unless the request carries an authenticated user token.
  • Portal-link abuse protection: send-donor-magic-link now requires authenticated caller context (org member or linked donor self), closing unauthenticated donor-email probing/spam paths.
  • Success CTA update: standalone success page keeps a direct "Donor Portal Login" action and no longer triggers unauthenticated magic-link sends client-side.
  • Purpose scope validation: purpose IDs are now validated as org-scoped or global (not merely "exists"), both during payment initialization and webhook donation posting.

Recent Updates (April 7, 2026)

Lazy-loaded Stripe checkout (embed performance)

  • What: EmbeddedPaymentForm and the payment-step `StripeProvider` wrapper live in `DonorLandingEmbeddedCheckout.tsx`. `DonorLandingPage` imports that module with `lazyWithRetry` + `Suspense` when `showPaymentForm && paymentClientSecret` (all three layouts: embed, campaign, default).
  • Why: Keeps `@stripe/react-stripe-js` / `vendor-stripe` off the initial `DonorLandingPage` chunk until the donor continues to payment.
  • See also: 10-PUBLIC-DONATION-PAGE.md (Performance), DEVELOPER-PLAYBOOK incident log Apr 7.

Recent Updates (Apr 2026)

Footer alignment cleanup

  • The public giving-page footer now uses a stable desktop 3-column row so the copyright, tax copy, and org identity sit straight across instead of appearing slanted due to asymmetric column sizing.
  • The SEO/footer branding block (PublicFooter) remains separate below the donation-page footer content.

Recent Updates (March 25, 2026)

Recurring billing day & embed selects (scroll / iframe UX)

  • Problem: Billing day dropdown (29 rows: 1–28 + last day) and long purpose lists could appear huge, clip in embedded iframes, or lose stacking when SelectContent used a custom style (React replaced default z-index / max-height entirely).
  • Fix: (1) components/ui/select.tsx — merge default and caller style; default collisionPadding={12}; viewport overflow-y-auto + min-h-0. (2) BillingDaySelect shared component + getOrdinalSuffix export for success copy. (3) DonorLandingPage / DonationForm use BillingDaySelect; purpose selects use max-h-[min(40vh,12rem)]. (4) Embed: onOpenChange on billing day and purpose Select triggers debounced postMessage resize so hosts that implement the listener get extra height when menus open.
  • Files: select.tsx, BillingDaySelect.tsx, DonorLandingPage.tsx, DonationForm.tsx, DEVELOPER-PLAYBOOK.md §2/§24, 10-PUBLIC-DONATION-PAGE.md.

Overview

The Donor Landing Page is the public-facing donation page that donors see when they visit a nonprofit's custom donation URL. It displays campaign information, progress toward goals, and a donation form that integrates with the connected payment processor (Stripe).

Recent Updates (March 13, 2026)

Proration Bug Fix + Billing Schedule UX

  • P0: Proration charged partial month instead of full amountcreate-payment-intent used proration_behavior: 'create_prorations' with a future billing_cycle_anchor. Stripe prorated the first invoice for the stub period (e.g. $165.78 instead of $206.10 for a $200+fee subscription created Mar 13 with anchor Apr 8). Donors expected the full amount. Fixed: changed to proration_behavior: 'none' — first invoice charges the full monthly amount immediately, future invoices shift to the anchor date. NEVER use create_prorations for donation subscriptions.
  • P0: `calculateNextAnchorTimestamp` used server-local time — Edge function runtime timezone could drift. Fixed to use explicit UTC (Date.UTC()) and return both Unix timestamp and ISO date string for the frontend.
  • P1: Success screens now show billing schedule — Standalone and embed success screens display "Next charge: April 8, 2026, then the 8th of each month" for recurring donations. nextChargeDate and billingAnchorDay added to PaymentIntentResponse and PaymentIntentResult.
  • P1: `DonationSuccess.tsx` shows billing day — Standalone success page shows "Billed on the 8th of each month" when billingAnchorDay is available from get-donation-details.
  • P2: Ordinal suffixes fixed — Inline ternary day === 1 ? '1st' : day === 2 ? '2nd' : day === 3 ? '3rd' : ${day}th produced "21th", "22th", "23th". Replaced with getOrdinalSuffix() helper that handles 11th–13th special cases and all -1st/-2nd/-3rd suffixes. Fixed in all 4 billing day selectors (3 in DonorLandingPage, 1 in DonationForm).
  • P2: `handleInvoicePaid` base_amount/processing_fee mismatch — Subscription metadata stores per-cycle constants (base=200, fee=6.10). If the invoice amount differed from the cycle total (prorated legacy invoices), the donation record had amount: 165.78 but base_amount: 200. Fixed: if invoice amount doesn't match metadata total, derive base/fee proportionally from the actual amount.
  • P2: `billingAnchorDay` wired through `get-donation-details` — Edge function now reads billing_anchor_day from Stripe session metadata and includes it in response. DonationDetails interface updated in both EF and frontend.

Earlier March 13 — Billing Day Selector Overhaul

  • P0: Billing day was never enforcedcreate-payment-intent stored the donor's selected billing day in Stripe metadata but never set billing_cycle_anchor on the subscription. Fixed: now applies billing_cycle_anchor via calculateNextAnchorTimestamp().
  • P1: Replaced 3-button picker with day-of-month Select — The old "1st of Month / Mid-Month / End of Month" 3-button layout was replaced with a <Select> dropdown offering days 1–28 plus "Last day of each month" (value 31). Applied to all 3 render paths in DonorLandingPage.tsx (embed, campaign, default) and DonationForm.tsx.
  • P1: Self-service donation amount change — Donors can now change their recurring donation amount from the Donor Portal without opening the Stripe Customer Portal. New "Change Amount" button on the subscription card opens an inline form. Calls manage-stripe-subscription EF with action: 'update_amount'. Self-service auth added to the EF (matching create-setup-intent pattern).

Files Modified (Proration Fix)

  • supabase/functions/create-payment-intent/index.tsproration_behavior: 'none', UTC timestamps, billingAnchorDay/nextChargeDate in response
  • supabase/functions/stripe-webhook/index.tshandleInvoicePaid proportional base/fee derivation
  • supabase/functions/get-donation-details/index.tsbillingAnchorDay in response interface + wiring
  • src/lib/db/stripe.tsbillingAnchorDay/nextChargeDate in PaymentIntentResult
  • src/features/donors/components/DonorLandingPage.tsxgetOrdinalSuffix() helper, formatNextChargeDate(), billing schedule on success screens, nextChargeDate state
  • src/features/donors/components/DonationSuccess.tsxbillingAnchorDay in interface + display
  • src/components/shared/DonationForm.tsx — Fixed ordinal suffix

Files Modified (Earlier Billing Day Overhaul)

  • supabase/functions/create-payment-intent/index.ts — Added calculateNextAnchorTimestamp(), applied billing_cycle_anchor
  • supabase/functions/manage-stripe-subscription/index.ts — Added self-service auth (donor_users check, update_amount only for self-service)
  • src/features/donors/components/DonorLandingPage.tsx — Replaced 3× billing day 3-button pickers with Select dropdowns (1–28 + last day of month)
  • src/components/shared/DonationForm.tsx — Same Select replacement + added Select component imports
  • src/features/donors/components/DonorPortal.tsx — Added "Change Amount" button, inline form, handleChangeAmount handler, manageStripeSubscription import

Earlier Updates (March 12, 2026)

Donation Success Page Overhaul

  • P0: Contact Us footer emptycontactEmail was never wired through the data pipeline. The organizations table has no email column — admin email is now fetched from organization_users (role=parent_org) + users table, with parent org inheritance for child funds. Wired through PublicDonationPage.tsx config builder and get-donation-details edge function.
  • P0: Confusing "Your Impact" stats removed — The inline success screen showed "Contributed: $1.00" and "Total Donors: 1" which simply echoed back the donation amount + incremented the page's donor count. This was misleading (appeared to be the donor's profile stats) and was not populated from the donor's actual giving history. Removed entirely — unauthenticated donors should not see aggregate stats that could be confused with their personal data.
  • P0: `DonationSuccess.tsx` standalone had no org contact info — Was using generic PublicFooter ("Powered by Alignmint") with zero org details. Now renders full 3-column org footer (org name, Contact Us with email/phone/address, Tax Information with EIN) matching the DonorLandingPage inline success footer pattern.
  • P1: Donor Portal login button added — "Access Donor Portal" button on success page calls send-donor-magic-link edge function with donor's email + org ID. Shows loading/sent states. Lets donors immediately access their giving history, tax receipts, and recurring management.
  • P1: Recurring-specific content — Recurring donations now show "You can manage or cancel your recurring donation anytime from your email receipt or by contacting {contactEmail}." One-time donations don't show this.
  • P1: `history.back()` fallback fixed — "Make Another Donation" / "Go Back" now checks window.history.length > 1 before calling history.back(). Falls back to getalignmint.org for direct-navigation users.
  • P2: `taxDeductible` no longer hardcodedget-donation-details edge function now reads is_taxable from the donation record instead of always returning true.
  • P2: Tax ID shown in footer — EIN from org (with parent inheritance) displayed in footer Tax Information section.
  • P2: `fadeInBlurStyle` added — Standalone success page now uses fade-in animation matching other public pages.
  • P3: Contact links clickable — Email uses mailto:, phone uses tel: links with hover effects.
  • P3: Removed unused `Target` import from DonorLandingPage.tsx (was only used in removed Impact Recap).

Files Modified

  • supabase/functions/get-donation-details/index.ts — Added contactEmail, contactPhone, mailingAddress, taxId to response; reads is_taxable from donation; fetches org contact info with parent inheritance; fetches admin email via organization_users
  • src/features/donors/components/DonationSuccess.tsx — Full rewrite: org contact footer, portal login button, recurring text, history.back() fix, fadeInBlurStyle, removed confusing impact stats
  • src/features/donors/components/DonorLandingPage.tsx — Removed "Your Impact" stats section from inline success; fixed Contact Us footer to only render when contact info exists; added mailto/tel links; removed unused Target import
  • src/features/events/components/PublicDonationPage.tsx — Wired contactEmail from org admin user into config

Earlier Updates (March 9, 2026)

Embed Iframe Blocking Fix

  • P0: `ERR_BLOCKED_BY_RESPONSE` resolved — Vercel applies ALL matching header rules (not first-match). Two rules with source: "/(.*)" sent conflicting X-Frame-Options: ALLOWALL + DENY simultaneously. Browsers reject conflicting values per RFC 7034. Fix: replaced query-based ?embed=true detection with host-based mutual exclusionhas: "host" = "donate.alignmint.app" on permissive rule, missing: "host" on DENY rule. Only ONE rule fires per request. All donate.alignmint.app pages are now always embeddable without requiring ?embed=true
  • Public org key migrationDonorPageManager and embed generators now prefer organizations.public_org_key for newly emitted links while keeping legacy 6-character UUID-prefix URLs readable during the migration window.
  • Currency formatting — Replaced ~20 hardcoded $ symbols with formatCurrency()/formatCurrencyStatic() across all 3 render paths (embed, standalone success, campaign/default)
  • Theme compliance — Replaced hardcoded #ec4899 hex color with text-primary class (§19)

Earlier Updates (February 11, 2026)

Embed Layout Customization

  • Configurable form width — New maxWidth URL parameter allows embeds to expand beyond the previous 448px card limit
  • Banner/hero image support — Embed mode now renders the hero image as a banner above the card when available; controlled via showBanner parameter
  • Logo sizing — New logoSize URL parameter (sm, md, lg) controls nonprofit logo display size in embed mode
  • Default iframe max-width increased — Generated embed code now defaults to 700px (was 600px)
  • Dynamic card width — Card max-width is now driven by the maxWidth URL parameter instead of hardcoded max-w-md

Inline Payment for Embed Mode

  • All modes now use PaymentIntent + PaymentElement (inline checkout)
  • Removed Stripe Checkout redirect — embed mode no longer opens a new tab
  • Fixes popup blocker issue — browsers were blocking window.open from within iframes
  • Compact embed success state — success confirmation renders inline within the iframe
  • Updated iframe permissionsallow="payment *; publickey-credentials-get *" for 3D Secure support
  • `showSuccess` gated for embed — standalone success page only renders in non-embed mode

Earlier Updates (February 2, 2026)

Payment Flow Clarification

  • Standard pages use PaymentIntent + PaymentElement (inline checkout)
  • Embed mode previously used Stripe Checkout (opened in a new tab — now removed)

Earlier Updates (January 2026)

Purpose Selector (Jan 31, 2026)

  • Fund Earmarking: Donors can now select a specific purpose/fund for their donation
  • Dynamic Dropdown: Purpose list fetched from purposes table, filtered by organization
  • Database Integration: Selected purpose_id stored in donation record for reporting
  • Metadata Flow: Purpose ID passed through payment metadata to webhook
  • Recurring Support: Purpose selection works for both one-time and recurring donations

Embed Scroll Fix (Jan 29, 2026)

  • Scroll Prevention: Fixed issue where embedded donation forms would scroll when mouse moved over them
  • Debounced Height Updates: Height communication to parent window now debounced to prevent jitter
  • Updated Embed Code: Generated embed code now includes scrolling="no" and overflow: hidden
  • Stable Measurement: Uses data-embed-content marker for accurate height calculation

Tax Compliance Support (Jan 22, 2026)

  • Transaction Type Selection: Pages can now be configured as Donation (tax-deductible), Service, Product, or Fee
  • Sales Tax Collection: Non-donation transaction types can enable Stripe Tax for automatic sales tax calculation
  • Dynamic Checkout: Payment flow passes transactionType and collectSalesTax to Edge Function
  • Stripe Tax Integration: When enabled, Stripe automatically calculates and collects applicable sales tax

Phase 2 Improvements - Embed Theming (Jan 19, 2026)

  • Neutral Embed Styling: Embedded donation forms no longer force the organic theme
  • Custom Color Support: Embeds can be themed via URL parameters to match host page styling
  • Transparent Background: Embed background is transparent by default for seamless integration
  • URL Parameters for Theming: primary, bg, fg, cardBg, btnText (hex codes without #)

Phase 1 Improvements - Conversion Optimization

  • Organic Theme Enforcement: Standalone public pages display in organic theme via data-theme="organic" wrapper
  • FAQ Section: Collapsible accordion with 6 essential donor questions (tax-deductible, security, receipts, etc.)
  • Enhanced Trust Indicators: "Give With Confidence" badges (Secure, Tax Receipt, 100% Impact)
  • Payment Method Display: Shows accepted cards (Visa, MC, Amex, Discover) and digital wallets (Apple Pay, Google Pay)
  • Improved Fee Messaging: Dynamic messaging when "cover fees" is checked, showing gratitude and impact

URL Structure

Donation pages are accessed via public URLs:

  • Subdomain: https://{nonprofit-slug}.donate.alignmint.org/{page-slug}
  • Path-based: https://donate.alignmint.org/{nonprofit-slug}/{page-slug}

Examples:

  • https://awakenings.donate.alignmint.org/annual-gala-2025
  • https://donate.alignmint.org/awakenings/annual-gala-2025

UI Features

Header

  • Nonprofit logo and name
  • "Secure Donation" badge with shield icon
  • Sticky on scroll

Hero Section

  • Full-width hero image from campaign configuration
  • Optional hero video (from VideoBlast library or direct upload)
  • If both image and video provided, video takes priority
  • Campaign title and description overlay
  • Gradient overlay for text readability

Campaign Progress Card

  • Amount raised vs goal
  • Progress bar with percentage
  • Donor count
  • Days remaining (if applicable)

Donation Form

  • Suggested Amounts: Configurable preset buttons (sorted highest first)
  • Custom Amount: Optional text input for custom donations
  • Purpose Selector: Dropdown to designate gift purpose/fund (populated from purposes table)
  • Recurring Toggle: Monthly recurring option (if enabled)
  • Cover Processing Fee: Enhanced checkbox with dynamic messaging
  • Shows calculated fee amount when donation amount is entered
  • When checked: Thanks donor and confirms 100% impact message
  • When unchecked: Explains what processing fees are
  • Fee calculation: 2.9% + $0.30 per transaction
  • Donor Info: First name, last name, email
  • Donate Button: Triggers payment processor checkout

FAQ Section

Collapsible accordion answering common donor questions:

  • Is my donation tax-deductible?
  • How will my donation be used?
  • Is my payment information secure?
  • Will I receive a receipt?
  • Can I change or cancel my recurring donation? (conditional)
  • Does my employer match donations?

Trust Indicators

  • Give With Confidence section with icon badges:
  • 🔒 Secure - 256-bit encryption
  • ✅ Tax Receipt - Sent immediately
  • 🏆 100% Impact - Direct to mission
  • Payment method badges (Visa, Mastercard, Amex, Discover)
  • Digital wallet support indicators (Apple Pay, Google Pay)

Success Screen

  • Thank you message (configurable)
  • Donation amount confirmation
  • Receipt email confirmation
  • "Make Another Donation" button

Data Requirements

DonorLandingPageConfig Interface

interface DonorLandingPageConfig {
  id: string;
  slug: string;
  nonprofitSlug: string;
  nonprofitName: string;
  nonprofitLogo?: string;
  title: string;
  description: string;
  heroImage: string;
  heroVideo?: string; // Optional video URL (YouTube/Vimeo embed or VideoBlast)
  goalAmount: number;
  raisedAmount: number;
  donorCount: number;
  daysRemaining?: number;
  suggestedAmounts: number[];
  allowCustomAmount: boolean;
  allowRecurring: boolean;
  thankYouMessage: string;
  taxId?: string;
  paymentProcessor: {
    connected: boolean;
    processor: 'stripe' | 'paypal' | 'square' | null;
    processorName: string;
  };
  // Tax compliance fields (added Jan 2026)
  transactionType?: 'donation' | 'service' | 'product' | 'fee';
  collectSalesTax?: boolean;
}

Payment Flow

Standard Mode (Standalone Page)

1. Donor selects amount and enters info 2. Clicks "Donate Now" 3. System calls create-payment-intent Edge Function 4. Stripe PaymentElement renders inline 5. On success, payment_intent.succeeded webhook creates donation + journal entry 6. Donor sees inline success screen

Embed Mode (iframe)

1. Donor fills out embedded form 2. Clicks "Donate Now" 3. System calls create-payment-intent Edge Function (same as standard mode) 4. Stripe PaymentElement renders inline within the iframe 5. On success, payment_intent.succeeded webhook creates donation + journal entry 6. Compact success confirmation renders inline within the iframe

API Endpoints

# Standard flow (PaymentElement)
POST /functions/v1/create-payment-intent
{
  amount: number,
  coverFee: boolean,
  donorEmail: string,
  donorName: string,
  organizationId: string,
  purposeId?: string,
  isRecurring: boolean,
  recurringFrequency?: string
}

# Embed flow (now uses same endpoint as standard)
POST /functions/v1/create-payment-intent
{
  amount: number,
  coverFee: boolean,
  donorEmail: string,
  donorName: string,
  organizationId: string,
  purposeId?: string,
  isRecurring: boolean
}

State Management

Local State

  • selectedAmount - Currently selected preset amount
  • customAmount - Custom amount input value
  • isRecurring - Monthly recurring toggle
  • coverFee - Cover processing fee toggle (default: true)
  • selectedPurposeId - Selected purpose/fund for donation (from purposes table)
  • purposes - List of available purposes for the organization
  • isProcessing - Payment processing state
  • showSuccess - Success screen visibility
  • donorInfo - First name, last name, email

Business Rules

  • Suggested amounts display in descending order (highest first)
  • Custom amount only available if allowCustomAmount is true
  • Recurring option only shown if allowRecurring is true
  • Cover processing fee checkbox always shown (default: checked)
  • Processing fee = (amount × 2.9%) + $0.30
  • Total donation = base amount + processing fee (if coverFee is true)
  • Email is required for all donations
  • Payment processor must be connected for donations to work
  • Tax ID displayed if provided

Error Handling

| Scenario | Behavior |
|----------|----------|
| No amount selected | Toast: "Please select or enter a donation amount" |
| No email entered | Toast: "Please enter your email address" |
| Payment processor not connected | Toast: "Payment processing is not available" |
| Checkout creation fails | Toast with error message |

Security

  • HTTPS required
  • No sensitive payment data stored locally
  • All payment processing via Stripe (PaymentElement/Checkout APIs, PCI compliant)
  • Secure donation badge displayed
  • return_url values are sanitized and allowlisted before navigation
  • Additional trusted return origins can be configured via VITE_ALLOWED_PUBLIC_RETURN_ORIGINS (comma-separated)
  • Public receipt lookup requires session_id; unauthenticated requests receive redacted donor fields

Embed Mode

When accessed with ?embed=true, the donation form renders in a minimal layout suitable for iframe embedding.

Embed Features

  • No header/footer - Minimal UI for seamless integration
  • Transparent background - Blends with host page
  • Scroll prevention - Embedded form does not scroll internally (fixed Jan 2026)
  • Dynamic height - Sends debounced postMessage for iframe resizing
  • Custom theming - Colors can be customized via URL parameters
  • Inline PaymentElement - Stripe payment form renders directly within the iframe (no redirect)
  • Banner image - Hero image renders as a banner above the card (configurable via showBanner)
  • Configurable width - Form card max-width adjustable via maxWidth URL parameter
  • Logo sizing - Nonprofit logo size adjustable via logoSize URL parameter (sm/md/lg)

Scroll Prevention (Jan 2026 Fix)

The embed mode includes multiple layers of scroll prevention to ensure the donation form integrates seamlessly without unwanted scrolling:

1. CSS overflow hidden - Applied to html, body, and container elements 2. iframe scrolling="no" - Disabled in generated embed code 3. Debounced height updates - Prevents height "bouncing" that can cause scroll jitter 4. Stable height measurement - Uses data-embed-content marker for accurate sizing

Payment Flow in Embed Mode

Embed mode uses the same inline PaymentElement as standalone mode:

1. Donor fills out amount and info in the embedded form 2. Clicks "Donate Now" 3. System calls create-payment-intent and receives a clientSecret 4. Stripe PaymentElement renders inline within the iframe card 5. Donor completes payment without leaving the page 6. Compact success confirmation displays inline

> Note: The iframe must include allow="payment *; publickey-credentials-get *" for Stripe's PaymentElement and 3D Secure to work correctly. The generated embed code includes this automatically.

Custom Theming Parameters

Add these parameters to the embed URL to match your website's theme. All colors are hex codes without the # symbol.

| Parameter | Description | Example |
|-----------|-------------|---------|
| `primary` | Button and accent color | `primary=0066cc` |
| `bg` | Background color | `bg=ffffff` |
| `fg` | Text color | `fg=333333` |
| `cardBg` | Card background color | `cardBg=f5f5f5` |
| `btnText` | Button text color | `btnText=ffffff` |

Layout Customization Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `maxWidth` | number (px) | `448` (28rem) | Maximum width of the form card |
| `logoSize` | `sm` / `md` / `lg` | `sm` | Logo display size (24px / 40px / 56px) |
| `showBanner` | `true` / `false` | `true` (if hero image exists) | Show hero image as banner above the card |

Example Embed URL with Custom Colors

https://donate.alignmint.app/abc123/nonprofit/donate?embed=true&primary=0066cc&bg=f5f5f5&fg=333333

Example Embed URL with Layout Customization

https://donate.alignmint.app/abc123/nonprofit/donate?embed=true&maxWidth=800&logoSize=lg&showBanner=true

Default Behavior (No Color Parameters)

If no color parameters are provided, the embed uses neutral styling:

  • Background: Transparent
  • Card: White (#ffffff)
  • Text: Dark gray (#1f2937)
  • Primary/Buttons: Gray (#374151)
  • Card max-width: 448px (28rem)
  • Logo size: Small (24px)
  • Banner: Shown if hero image exists

This neutral styling works well on most light-themed websites.

Related Documentation


Synced from IFMmvp-Frontend documentation: pages/donor-hub/08-DONOR-LANDING-PAGE.md

Ready to Get Started?

See how Alignmint can simplify your nonprofit's operations. Schedule a free demo with our team and we'll walk you through everything.

Questions? Email us at steven@getalignmint.org

Ready to get started?Start Plus Trial