Marketing Footer
A complete marketing footer section, ready to adapt to your product.
Make it yours.
Install the editable source and its dependencies into your React + Tailwind project.
Scroll horizontally for long lines
pnpm dlx shadcn@4.0.8 add http://localhost:3000/r/marketing-footer.jsonUse it
Scroll horizontally for long lines
"use client";
import { MarketingFooter } from "@/components/jez-ui/blocks/marketing-footer";
export default function Example() {
return (
<>
<MarketingFooter />
</>
);
}
Compose your own
These styled parts are included in the same install. Use children to build your layout; add className only when you want an override.
Scroll horizontally for long lines
"use client";
import {
MarketingFooter,
MarketingFooterBrand,
MarketingFooterLinks,
MarketingFooterNote,
} from "@/components/jez-ui/blocks/marketing-footer";
export default function Example() {
return (
<MarketingFooter>
<MarketingFooterBrand />
<MarketingFooterLinks />
<MarketingFooterNote />
</MarketingFooter>
);
}
Scroll horizontally for long lines
import { MarketingFooter, MarketingFooterNavigation, MarketingFooterBrand, MarketingFooterLinks, MarketingFooterNote } from "@/components/jez-ui/blocks/marketing-footer";Props & types
Scroll horizontally for long lines
export type MarketingFooterOptions = {
brand?: string;
items?: { label: string; href: string }[];
className?: string;
};
export type MarketingFooterProps = Omit<
React.ComponentProps<"footer">,
keyof MarketingFooterOptions
> &
MarketingFooterOptions;
MarketingFooterPropsSource
View 2 source files
registry/blocks/marketing-footer.tsx
Scroll horizontally for long lines
"use client";
import * as React from "react";
import { cn } from "../ui/utils";
export type MarketingFooterOptions = {
brand?: string;
items?: { label: string; href: string }[];
className?: string;
};
export type MarketingFooterProps = Omit<
React.ComponentProps<"footer">,
keyof MarketingFooterOptions
> &
MarketingFooterOptions;
function useMarketingFooterModel({
brand = "Forma",
items = [
{ label: "Contact", href: "#contact" },
{ label: "About", href: "#about" },
],
className,
children,
...rootProps
}: MarketingFooterProps) {
return { brand, items, className, children, rootProps };
}
const MarketingFooterCompositionContext = React.createContext<ReturnType<
typeof useMarketingFooterModel
> | null>(null);
function useMarketingFooterComposition() {
const context = React.useContext(MarketingFooterCompositionContext);
if (!context)
throw new Error("MarketingFooter parts must be inside MarketingFooter.");
return context;
}
export function MarketingFooter(props: MarketingFooterProps) {
const model = useMarketingFooterModel(props);
const { className, rootProps, children } = model;
return (
<MarketingFooterCompositionContext.Provider value={model}>
<footer
{...rootProps}
className={cn(
"mt-16 flex flex-wrap items-center justify-between gap-6 border-t border-border py-8 text-sm",
className,
)}
>
{children !== undefined ? (
children
) : (
<>
<MarketingFooterBrand />
<MarketingFooterLinks />
<MarketingFooterNote />
</>
)}
</footer>
</MarketingFooterCompositionContext.Provider>
);
}
export function MarketingFooterNavigation({
className,
...props
}: React.ComponentProps<"nav">) {
return (
<nav
data-slot="marketing-footer-navigation"
className={cn("flex gap-5", className)}
{...props}
/>
);
}
export function MarketingFooterBrand({
children,
...props
}: Partial<React.ComponentProps<"span">> & { children?: React.ReactNode }) {
const { brand } = useMarketingFooterComposition();
return (
<span
{...props}
className={cn("font-display text-xl font-medium", props.className)}
>
{children === undefined ? brand : children}
</span>
);
}
export function MarketingFooterLinks({
children,
...props
}: Partial<React.ComponentProps<typeof MarketingFooterNavigation>> & {
children?: React.ReactNode;
}) {
const { items } = useMarketingFooterComposition();
return (
<MarketingFooterNavigation aria-label="Footer" {...props}>
{children === undefined
? items.map((i) => (
<a key={i.href} href={i.href}>
{i.label}
</a>
))
: children}
</MarketingFooterNavigation>
);
}
export function MarketingFooterNote({
children,
...props
}: Partial<React.ComponentProps<"span">> & { children?: React.ReactNode }) {
return (
<span
{...props}
className={cn("text-xs text-muted-foreground", props.className)}
>
{children === undefined ? "A Jez UI demo template." : children}
</span>
);
}
registry/ui/utils.ts
Scroll horizontally for long lines
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...values: ClassValue[]) {
return twMerge(clsx(values));
}
Dependencies
clsx@2.1.1 · tailwind-merge@3.5.0
Accessibility & behaviour
Provide meaningful labels and preserve keyboard focus styles. Check contrast when customising theme colours.
Read the accessibility and performance guide →