Skip to content

Footer Links

BlockMantine ≥ 9MantineProvider

Multi-column site footer with a brand block, titled link groups, copyright line and social icons — all consumer-supplied.

Install

One command copies the item's source into your project, where you own and edit it.

Terminal window
npx manteen add @house/footer-links

Dependencies

  • @mantine/core@^9npm

Installing this item also installs @house/mantine-ui-license from the registry.

Preview

Usage

A copy-ready example published by the registry author. Imports use the aliases Manteen configures at init.

footer-links.usage.tsx
import { Text } from "@mantine/core";
import { IconBrandInstagram, IconBrandTwitter, IconBrandYoutube } from "@tabler/icons-react";
import {
FooterLinks,
type FooterLinksGroup,
type FooterLinksSocialLink,
} from "@/components/ui/footer-links";
const groups: FooterLinksGroup[] = [
{
title: "About",
links: [
{ label: "Features", href: "/features" },
{ label: "Pricing", href: "/pricing" },
{ label: "Support", href: "/support" },
{ label: "Forums", href: "/forums" },
],
},
{
title: "Project",
links: [
{ label: "Contribute", href: "/contribute" },
{ label: "Media assets", href: "/media" },
{ label: "Changelog", href: "/changelog" },
{ label: "Releases", href: "/releases" },
],
},
{
title: "Community",
links: [
{ label: "Join Discord", href: "https://discord.gg/acme" },
{ label: "Follow on Twitter", href: "https://twitter.com/acme" },
{ label: "Email newsletter", href: "/newsletter" },
{ label: "GitHub discussions", href: "https://github.com/acme/acme/discussions" },
],
},
];
const socialLinks: FooterLinksSocialLink[] = [
{
href: "https://twitter.com/acme",
label: "Twitter",
icon: <IconBrandTwitter size={18} stroke={1.5} />,
},
{
href: "https://youtube.com/@acme",
label: "Youtube",
icon: <IconBrandYoutube size={18} stroke={1.5} />,
},
{
href: "https://instagram.com/acme",
label: "Instagram",
icon: <IconBrandInstagram size={18} stroke={1.5} />,
},
];
export function SiteFooter() {
return (
<FooterLinks
logo={
<Text fw={700} size="lg">
Acme
</Text>
}
tagline="Build fully functional accessible web applications faster than ever"
groups={groups}
copyright="© 2026 Acme. All rights reserved."
socialLinks={socialLinks}
/>
);
}

Props

Author-documented props, carried verbatim from the registry item.

PropTypeDefaultDescription
logoReactNodeRendered at the start of the brand block; nothing renders when omitted.
taglinestringShort description under the logo; omitted when unset.
groups*readonly FooterLinksGroup[]Titled link columns, each { title: string; links: readonly FooterLinksLink[] }; this is the component's whole point.
copyrightstringCopyright/legal line in the bottom bar; omitted when unset.
socialLinksreadonly FooterLinksSocialLink[]{ href, icon, label } per entry; label becomes the icon link's aria-label. The entire bottom-bar social row is omitted when unset or empty.

* required

Styling

No public Styles API is declared. Installed CSS remains editable because your project owns the source; internal class names are implementation details, not a customization contract.

Source

2 installable files ship with this item.

registry/mantine-ui/footer-links/footer-links.tsxcomponent · 3.1 kB · tsx
/**
* Adapted from Mantine UI's FooterLinks at
* ffbf61c559f374a7ea28fcf00355e84dcbe9a908. MIT licensed; see
* LICENSES/MANTINE-UI.txt after installation.
*/
import { ActionIcon, Container, Group, Text } from "@mantine/core";
import type { ReactNode } from "react";
import classes from "./footer-links.module.css";
export interface FooterLinksLink {
label: string;
href: string;
}
export interface FooterLinksGroup {
title: string;
links: readonly FooterLinksLink[];
}
export interface FooterLinksSocialLink {
href: string;
icon: ReactNode;
/** Accessible name for the icon-only link, e.g. "Twitter". */
label: string;
}
export interface FooterLinksProps {
/** Rendered at the start of the brand block; nothing renders when omitted. */
logo?: ReactNode;
/** Short description under the logo; omitted when unset. */
tagline?: string;
/** Titled link columns. This is the component's whole point. */
groups: readonly FooterLinksGroup[];
/** Copyright / legal line; omitted when unset. */
copyright?: string;
/** Social icon links; the row is omitted when unset or empty. */
socialLinks?: readonly FooterLinksSocialLink[];
}
export function FooterLinks({ logo, tagline, groups, copyright, socialLinks }: FooterLinksProps) {
const hasBrand = Boolean(logo || tagline);
const hasSocial = Boolean(socialLinks && socialLinks.length > 0);
const groupItems = groups.map((group) => {
const links = group.links.map((link) => (
<Text key={link.label} className={classes.link} component="a" href={link.href}>
{link.label}
</Text>
));
return (
<div className={classes.wrapper} key={group.title}>
<Text className={classes.title}>{group.title}</Text>
{links}
</div>
);
});
return (
<footer className={classes.footer}>
<Container className={classes.inner}>
{hasBrand && (
<div className={classes.logo}>
{logo}
{tagline && (
<Text size="xs" c="dimmed" className={classes.description}>
{tagline}
</Text>
)}
</div>
)}
<div className={classes.groups}>{groupItems}</div>
</Container>
{(copyright || hasSocial) && (
<Container className={classes.afterFooter}>
{copyright && (
<Text c="dimmed" size="sm">
{copyright}
</Text>
)}
{hasSocial && (
<Group gap={0} className={classes.social} justify="flex-end" wrap="nowrap">
{socialLinks?.map((social) => (
<ActionIcon
key={social.href}
size="lg"
color="gray"
variant="subtle"
aria-label={social.label}
component="a"
href={social.href}
>
{social.icon}
</ActionIcon>
))}
</Group>
)}
</Container>
)}
</footer>
);
}
registry/mantine-ui/footer-links/footer-links.module.cssstyle · 2.5 kB · css
/*
* Adapted from Mantine UI's FooterLinks at
* ffbf61c559f374a7ea28fcf00355e84dcbe9a908. MIT licensed; see
* LICENSES/MANTINE-UI.txt after installation.
*/
/* Upstream used postcss-preset-mantine's `$mantine-breakpoint-sm`; this
* registry ships plain CSS modules with no PostCSS preset, so the literal
* 48em default `sm` breakpoint value is inlined here (`var()` is invalid
* inside a media condition). See header-mega-menu.module.css for the same
* convention. Upstream's `margin-top: 120px` on `.footer` was outer layout
* margin imposed on the host page and is dropped here — a registry item
* must not push the page around. */
.footer {
padding-top: calc(var(--mantine-spacing-xl) * 2);
padding-bottom: calc(var(--mantine-spacing-xl) * 2);
background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6));
border-top: 1px solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-5));
}
.logo {
max-width: 200px;
}
@media (max-width: 48em) {
.logo {
display: flex;
flex-direction: column;
align-items: center;
}
}
.description {
margin-top: 5px;
}
@media (max-width: 48em) {
.description {
margin-top: var(--mantine-spacing-xs);
text-align: center;
}
}
.inner {
display: flex;
justify-content: space-between;
}
@media (max-width: 48em) {
.inner {
flex-direction: column;
align-items: center;
}
}
.groups {
display: flex;
flex-wrap: wrap;
}
@media (max-width: 48em) {
.groups {
display: none;
}
}
.wrapper {
width: 160px;
}
.link {
display: block;
color: light-dark(var(--mantine-color-gray-6), var(--mantine-color-dark-1));
font-size: var(--mantine-font-size-sm);
padding-top: 3px;
padding-bottom: 3px;
}
.link:hover {
text-decoration: underline;
}
.title {
font-size: var(--mantine-font-size-lg);
font-weight: 500;
font-family: var(--mantine-font-family-headings);
margin-bottom: calc(var(--mantine-spacing-xs) / 2);
color: light-dark(var(--mantine-color-black), var(--mantine-color-white));
}
.afterFooter {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: var(--mantine-spacing-xl);
padding-top: var(--mantine-spacing-xl);
padding-bottom: var(--mantine-spacing-xl);
border-top: 1px solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-4));
}
@media (max-width: 48em) {
.afterFooter {
flex-direction: column;
}
}
@media (max-width: 48em) {
.social {
margin-top: var(--mantine-spacing-xs);
}
}

Author notes

Adapted from Mantine UI FooterLinks at ffbf61c559…; the three hardcoded link groups became the groups prop, the upstream MantineLogo import became an optional logo slot, the tagline/copyright strings became optional props with no fake placeholder default, and the fixed social icons became a consumer-supplied socialLinks array.