shadimage
payload-components
blockcall-to-action-splitsource: ok · hit

Call To Action Split

Split Payload call-to-action block: heading and copy on one side, CTA links and assurance on the other.

npx shadcn add "https://www.payload-components.xyz/r/call-to-action-split.json"
free

Where it goes

cta

Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.

Files3 · source cached 10/9/2026, 9:22:23 AM

payload-components/source/blocks/shared/callToActionFields.ts
import type { Field } from 'payload'

/**
 * Shared field core for the Call To Action component family.
 *
 * Every call-to-action variant (call-to-action-centered, call-to-action-boxed,
 * call-to-action-signup, …) spreads these heading fields first and then appends
 * its own variant-specific shape — the CTA link group for the centered and boxed
 * layouts, or the email-capture fields for the signup layout. Editing the shared
 * title/description here updates every installed call-to-action block at once, so
 * the family never drifts field-by-field across a repo.
 *
 * Installed once per repo at `src/blocks/shared/callToActionFields.ts`; re-running
 * `payload-components add call-to-action-*` never overwrites a copy you have already edited.
 */
export const callToActionFields: Field[] = [
  {
    name: 'title',
    type: 'text',
    custom: { payloadComponents: { localization: 'localized' } },
    required: true,
  },
  {
    name: 'description',
    type: 'textarea',
    custom: { payloadComponents: { localization: 'localized' } },
  },
]
payload-components/source/blocks/CallToActionSplit/config.ts
import type { Block } from 'payload'

import { callToActionFields } from '@/blocks/shared/callToActionFields'
import { linkGroup } from '@/fields/linkGroup'

export const CallToActionSplit: Block = {
  slug: 'callToActionSplit',
  // Existing apps must migrate stored data before adopting this identifier:
  // https://www.payload-components.xyz/docs/registry#installed-source-and-migrations
  dbName: 'pc_cal_to_act_spl',
  interfaceName: 'CallToActionSplitBlock',
  fields: [
    // Shared call-to-action core (title, description). Variant-specific fields
    // follow; edit the shared shape in @/blocks/shared/callToActionFields.
    ...callToActionFields,
    {
      name: 'assurance',
      type: 'text',
      custom: { payloadComponents: { localization: 'localized' } },
      admin: {
        description: 'Optional reassurance line under the actions — pricing, timing, or terms.',
      },
    },
    linkGroup({
      overrides: {
        admin: {
          initCollapsed: true,
        },
        maxRows: 2,
        minRows: 1,
      },
    }),
  ],
  labels: {
    plural: 'Call To Action Split Blocks',
    singular: 'Call To Action Split',
  },
}
payload-components/source/blocks/CallToActionSplit/Component.tsx
import React from 'react'

import type { CallToActionSplitBlock as CallToActionSplitBlockData } from '@/payload-types'

import { CMSLink } from '@/components/Link'
import { cn } from '@/utilities/ui'

type Props = CallToActionSplitBlockData & {
  id?: string
  className?: string
  disableInnerContainer?: boolean
}

export const CallToActionSplitBlock: React.FC<Props> = ({
  assurance,
  className,
  description,
  disableInnerContainer,
  id,
  links,
  title,
}) => {
  return (
    <section className={cn('container', className)} id={id ? `block-${id}` : undefined}>
      <div className="overflow-hidden rounded-frame border border-border/70 bg-card/35 px-6 py-10 sm:px-8 lg:px-12 lg:py-14">
        <div
          className={cn(
            'flex flex-col gap-8 lg:flex-row lg:items-center lg:justify-between lg:gap-16',
            {
              'mx-auto max-w-6xl': !disableInnerContainer,
            },
          )}
        >
          <div className="flex max-w-2xl flex-col gap-4">
            <h2 className="text-4xl font-medium tracking-display text-balance sm:text-5xl">
              {title}
            </h2>

            {description ? (
              <p className="text-base leading-7 text-muted-foreground sm:text-lg">{description}</p>
            ) : null}
          </div>

          {links && links.length > 0 ? (
            <div className="flex shrink-0 flex-col gap-3">
              <div className="flex flex-col gap-3 sm:flex-row lg:justify-end">
                {links.map(({ link }, index) => (
                  <CMSLink
                    key={index}
                    appearance={link.appearance === 'outline' ? 'outline' : 'default'}
                    {...link}
                  />
                ))}
              </div>
              {assurance ? (
                <p className="text-sm leading-6 text-muted-foreground lg:text-end">{assurance}</p>
              ) : null}
            </div>
          ) : null}
        </div>
      </div>
    </section>
  )
}

More from payload-components

Browse all components in this library →