Launch UI
blockctasource: ok · refreshed
CTA Section
Call-to-action sections with various styles and glow effects.
npx shadcn add "https://www.launchuicomponents.com/r/cta.json"free
Where it goes
cta
Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.
Dependencies
Bundle weight · lightui-primitives@radix-ui/react-slot
Registry dependencies
https://launchuicomponents.com/r/button.jsonhttps://launchuicomponents.com/r/glow.json
Files4 · source cached 10/8/2026, 5:33:33 AM
components/sections/cta/default.tsx
import { cn } from "@/lib/utils";
import Glow from "../../ui/glow";
import { LinkButton, type LinkButtonProps } from "../../ui/link-button";
import { Section } from "../../ui/section";
interface CTAButtonProps extends Omit<LinkButtonProps, "children"> {
text: string;
}
interface CTAProps {
title?: string;
buttons?: CTAButtonProps[] | false;
className?: string;
}
const DEFAULT_CTA_BUTTONS: CTAButtonProps[] = [
{
href: "https://www.launchuicomponents.com/",
text: "Get Started",
variant: "default",
},
];
export default function CTA({
title = "Start building",
buttons = DEFAULT_CTA_BUTTONS,
className,
}: CTAProps) {
return (
<Section className={cn("group relative overflow-hidden", className)}>
<div className="max-w-container relative z-10 mx-auto flex flex-col items-center gap-6 text-center sm:gap-8">
<h2 className="max-w-[640px] text-3xl leading-tight font-semibold sm:text-5xl sm:leading-tight">
{title}
</h2>
{buttons !== false && buttons.length > 0 && (
<div className="flex justify-center gap-4">
{buttons.map((button) => (
<LinkButton
key={`${button.href}-${button.text}`}
variant={button.variant || "default"}
size="lg"
href={button.href}
icon={button.icon}
iconRight={button.iconRight}
>
{button.text}
</LinkButton>
))}
</div>
)}
</div>
<div className="absolute top-0 left-0 h-full w-full translate-y-[1rem] opacity-80 transition-all duration-500 ease-in-out group-hover:translate-y-[-2rem] group-hover:opacity-100">
<Glow variant="bottom" />
</div>
</Section>
);
}
components/ui/button.tsx
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
default:
"text-primary-foreground shadow-sm dark:hover:from-primary/80 hover:from-primary/70 dark:hover:to-primary/70 hover:to-primary/90 bg-linear-to-b from-primary/60 to-primary/100 dark:from-primary/100 dark:to-primary/70 border-t-primary",
destructive:
"bg-destructive/30 text-destructive-foreground shadow-xs hover:bg-destructive/90",
outline:
"border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
glow: "glass-4 hover:glass-5 shadow-md",
secondary:
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-foreground underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2",
xs: "h-7 rounded-md px-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-5",
icon: "size-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
);
function Button({
className,
variant,
size,
asChild = false,
...props
}: React.ComponentProps<"button"> &
VariantProps<typeof buttonVariants> & {
asChild?: boolean;
}) {
const Comp = asChild ? Slot : "button";
return (
<Comp
data-slot="button"
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
);
}
export { Button, buttonVariants };
components/ui/link-button.tsx
import { type VariantProps } from "class-variance-authority";
import { type ComponentProps, type ReactNode } from "react";
import { Button, buttonVariants } from "./button";
export interface LinkButtonProps {
href: string;
children: ReactNode;
variant?: VariantProps<typeof buttonVariants>["variant"];
icon?: ReactNode;
iconRight?: ReactNode;
size?: ComponentProps<typeof Button>["size"];
}
export function LinkButton({
href,
children,
variant = "default",
icon,
iconRight,
size = "lg",
}: LinkButtonProps) {
return (
<Button variant={variant} size={size} asChild>
<a href={href}>
{icon}
{children}
{iconRight}
</a>
</Button>
);
}
components/ui/glow.tsx
import { cva, VariantProps } from "class-variance-authority";
import React from "react";
import { cn } from "@/lib/utils";
const glowVariants = cva("absolute w-full", {
variants: {
variant: {
top: "top-0",
above: "-top-[128px]",
bottom: "bottom-0",
below: "-bottom-[128px]",
center: "top-[50%]",
},
},
defaultVariants: {
variant: "top",
},
});
function Glow({
className,
variant,
...props
}: React.ComponentProps<"div"> & VariantProps<typeof glowVariants>) {
return (
<div
data-slot="glow"
className={cn(glowVariants({ variant }), className)}
{...props}
>
<div
className={cn(
"from-brand-foreground/50 to-brand-foreground/0 absolute left-1/2 h-[256px] w-[60%] -translate-x-1/2 scale-[2.5] rounded-[50%] bg-radial from-10% to-60% opacity-20 sm:h-[512px] dark:opacity-100",
variant === "center" && "-translate-y-1/2",
)}
/>
<div
className={cn(
"from-brand/30 to-brand-foreground/0 absolute left-1/2 h-[128px] w-[40%] -translate-x-1/2 scale-200 rounded-[50%] bg-radial from-10% to-60% opacity-20 sm:h-[256px] dark:opacity-100",
variant === "center" && "-translate-y-1/2",
)}
/>
</div>
);
}
export default Glow;