Footer
Site footer with social media bar and multi-column link grid with alternating column widths
pnpm add @wandercom/design-system-web
The Footer component provides a comprehensive site footer with social media links, multi-column navigation, and branding. It supports both standard WanderOS and individual property sites through its variant system. Sites footers display a language selector when enabledLanguages contains at least two options. Use native language names for the option labels and use onLanguageChange to receive the selected language value.
import { Footer } from '@wandercom/design-system-web/blocks/footer';
import { Logo } from '@wandercom/design-system-web/ui/logo';
export function Example() {
return (
<Footer
topBar={{
title: 'Follow us',
links: [
{
label: 'X (Twitter)',
href: 'https://x.com/wander',
isExternal: true,
},
],
}}
sections={[
{
title: 'Company',
links: [{ label: 'About', href: '/about' }],
},
]}
logo={<Logo className="text-primary" />}
logoSize="sm"
/>
);
}The default footer variant includes trademark and copyright sections at the bottom and multi-column navigation. The Sites variant below is the documented social icon example.
<Footer
topBar={{
title: 'Follow us',
links: [
{
label: 'X (Twitter)',
href: 'https://x.com/wander',
isExternal: true,
},
{
label: 'Instagram',
href: 'https://instagram.com/wander',
isExternal: true,
},
{
label: 'TikTok',
href: 'https://tiktok.com/@wander',
isExternal: true,
},
{
label: 'LinkedIn',
href: 'https://linkedin.com/company/wander',
isExternal: true,
},
{
label: 'YouTube',
href: 'https://youtube.com/@wander',
isExternal: true,
},
],
}}
sections={[
{
title: 'Company',
links: [
{ label: 'About', href: '/about' },
{ label: 'Blog', href: '/blog' },
{
label: 'Contact',
key: 'contact',
onClick: () =>
toast.success({
label: "Copied to clipboard",
description: "Contact information copied",
}),
},
{ label: 'Careers', href: '/careers' },
{ label: 'Store', href: '/store' },
],
},
{
title: 'Resources',
links: [
{ label: 'Locations', href: '/locations' },
{ label: 'Licensing', href: '/licensing' },
{ label: 'Terms', href: '/terms' },
{ label: 'Privacy', href: '/privacy' },
{ label: 'Sitemap', href: '/sitemap' },
{ label: 'Events', href: '/events' },
],
},
{
title: 'Hosts',
links: [
{ label: 'WanderOS', href: '/sites' },
{ label: 'Operate with us', href: '/operate' },
{ label: 'List with us', href: '/listed' },
],
},
{
title: 'Partners',
links: [
{ label: 'Ambassadors', href: '/ambassadors' },
{ label: 'Travel Agents', href: '/travelagents' },
],
},
]}
logo={<Logo className="text-primary" />}
logoSize="sm"
/>A section can stack labelled clusters of links by providing groups instead of
a flat links array. Each group takes an optional heading (a plain,
non-interactive sub-heading exposed to assistive technology as text) plus its
own links — for example one group per contact office when a site lists several.
Spacing is applied per group, so a group without a heading is still
separated from the others; the first group stays flush with the section title.
<Footer
variant="sites"
sections={[
{
title: 'Contact us',
groups: [
{ links: [{ label: 'Send us a message', href: '/message' }] },
{
heading: 'Myrtle Beach office',
links: [
{ label: 'info@example.com', href: 'mailto:info@example.com' },
{ label: '603-770-9939', href: 'tel:6037709939' },
],
},
{
// No heading — still separated by group spacing.
links: [
{ label: 'hello@example.com', href: 'mailto:hello@example.com' },
{ label: '615-555-0142', href: 'tel:6155550142' },
],
},
],
},
]}
/>The Footer component supports two variants optimized for different use cases.
The default variant is designed for main Wander marketing and application sites. It features trademark and copyright sections at the bottom, and uses an alternating column width pattern for visual interest.
The Sites variant is optimized for individual property site footers. It replaces the trademark/copyright section with "Powered by WanderOS" branding, uses a custom 2-2-4 column span pattern for sections, and contains the social icon example. Consumers may pass any React icon node. For icon links, label supplies the accessible name and is visually hidden.
import { IconInstagram } from '@wandercom/design-system-icons/instagram';
import { IconLinkedin } from '@wandercom/design-system-icons/linkedin';
import { IconTiktok } from '@wandercom/design-system-icons/tiktok';
import { IconX } from '@wandercom/design-system-icons/x';
import { IconYoutube } from '@wandercom/design-system-icons/youtube';
<Footer
variant="sites"
enabledLanguages={[
{ label: "English", value: "en" },
{ label: "Español", value: "es" },
{ label: "Français", value: "fr" },
{ label: "Deutsch", value: "de" },
{ label: "Português", value: "pt" },
]}
logo={<WanderOSLogo className="text-primary" />}
logoSize="sm"
onLanguageChange={(value) => setLanguage(value)}
selectedLanguage={language}
topBar={{
title: 'Follow us',
links: [
{
label: 'X (Twitter)',
href: 'https://x.com/wander',
isExternal: true,
icon: <IconX className="size-5" />,
},
{
label: 'Instagram',
href: 'https://instagram.com/wander',
isExternal: true,
icon: <IconInstagram className="size-5" />,
},
{
label: 'TikTok',
href: 'https://tiktok.com/@wander',
isExternal: true,
icon: <IconTiktok className="size-5" />,
},
{
label: 'LinkedIn',
href: 'https://linkedin.com/company/wander',
isExternal: true,
icon: <IconLinkedin className="size-5" />,
},
{
label: 'YouTube',
href: 'https://youtube.com/@wander',
isExternal: true,
icon: <IconYoutube className="size-5" />,
},
],
}}
sections={[
{
title: 'Company',
links: [
{ label: 'About', href: '/about' },
{ label: 'List with us', href: '/list' },
{ label: 'Contact', href: '/contact' },
{ label: 'Property manager portal', href: '/property-manager' },
{ label: 'Owner portal', href: '/owner-portal' },
],
},
{
title: 'Resources',
links: [
{
label: 'Activities in Northern Kentucky',
href: '/northern-kentucky',
},
{ label: 'Activities in Nashville', href: '/nashville' },
{ label: 'Sitemap', href: '/sitemap' },
{ label: 'Terms of service', href: '/terms' },
{ label: 'Privacy policy', href: '/privacy' },
],
},
{
title: 'Contact us',
links: [
{ label: 'Send us a message', href: '/message' },
{
label: 'info@downtimevacationrentals.com',
href: 'mailto:info@downtimevacationrentals.com',
},
{ label: '603-770-9939', href: 'tel:6037709939' },
{
label: '219 Surfside DR, Myrtle Beach, South Carolina',
href: 'https://maps.google.com/?q=219+Surfside+DR,+Myrtle+Beach,+SC',
},
],
},
]}
/>The Sites variant displays the footer language selector next to the "Powered by WanderOS" attribution when enabledLanguages contains at least two options. Omit the prop, pass an empty array, or pass a single locale to hide the selector. Use each language's native name as its label, and use a stable locale code as its value.
const [language, setLanguage] = useState("en");
<Footer
variant="sites"
enabledLanguages={[
{ label: "English", value: "en" },
{ label: "Español", value: "es" },
{ label: "Français", value: "fr" },
]}
selectedLanguage={language}
onLanguageChange={(value) => setLanguage(value)}
/>onLanguageChange receives the selected locale value. The consuming site owns navigation: preserve the guest's current page when a localized version exists, and otherwise fall back to the localized homepage or an English equivalent.
The selector uses the design-system dropdown with keyboard navigation and a checkmark on the selected language. Its globe icon, current language, and chevron switch to the primary text color on hover and keyboard focus. The control is width-constrained for long native language names and wraps below the attribution when the footer becomes narrow. Override labels.languageSelectAriaLabel when the accessible label needs localization.
The Footer component supports two types of links to accommodate different interaction patterns.
Most footer links use the href prop to navigate to pages. For external links, set isExternal: true to add proper security attributes. Top bar links may pass any consumer-provided icon node; when icon is present, its label becomes the accessible name instead of visible text.
{ label: 'Privacy', href: '/privacy' }
{
label: 'Instagram',
href: 'https://instagram.com/wander',
isExternal: true,
icon: <IconInstagram className="size-5" />,
}For links that trigger actions instead of navigation (like copying to clipboard), use the onClick pattern. When using onClick, you must provide a unique key prop.
{
label: 'Contact',
key: 'contact',
onClick: () => toast.success({ label: 'Copied!' })
}The footer uses a responsive Grid layout with different patterns for each variant:
Default variant:
- Mobile (base): All sections span full width and stack vertically
- Tablet (md): Sections alternate between 2 and 4 columns for visual rhythm (1st: 2 cols, 2nd: 4 cols, 3rd: 2 cols, 4th: 4 cols)
- Desktop (lg): All sections span 2 columns within a 12-column grid
Sites variant:
- Custom column span pattern: 2-2-4 (first section: 2 cols, second: 2 cols, third: 4 cols)
The logo section always spans full width on mobile and 4 columns on desktop, remaining unaffected by section span patterns. Use logoSize to apply a small, medium, or large height to SVG and image logo content while preserving its aspect ratio. The default is sm.