I9kFooter โ
A page's bottom chrome. On its own it is a centred row of social links and a tagline; given link columns or a brand it becomes a multi-column site footer with a bottom bar.
ts
import { I9kFooter } from '@9klabs/design';Examples โ
Multi-column site footer โ
vue
<div style="position: relative; border: 1px solid var(--border-color); border-radius: var(--radius-md);">
<I9kFooter
tagline="Built with the 9k design system."
copyright="ยฉ 2026 Ismail9k"
brand-href="#"
brand-label="Ismail9k, Home"
:columns="[
{ id: 'explore', title: 'Explore', links: [
{ id: 'blog', label: 'Blog', href: '#blog' },
{ id: 'talks', label: 'Talks', href: '#talks' },
{ id: 'uses', label: 'Uses', href: '#uses' },
] },
{ id: 'connect', title: 'Connect', links: [
{ id: 'work', label: 'Let\'s work together', href: '#work' },
{ id: 'email', label: 'Email me', href: 'mailto:hello@ismail9k.com' },
] },
{ id: 'more', title: 'More from me', links: [
{ id: 'school', label: '9k School', href: 'https://9k.school', external: true, featured: true, emoji: '๐' },
{ id: 'labs', label: '9kLabs', href: 'https://the9klabs.com/', external: true },
] },
]"
:social-links="[
{ name: 'GitHub', url: 'https://github.com/ismail9k', icon: 'github' },
{ name: 'Instagram', url: 'https://instagram.com/ismail9k', icon: 'instagram' },
]"
>
<template #brand><I9kBrandWordmark /></template>
<template #extra
><I9kAskAi
heading="Ask AI about Ismail9k"
prompt="Who is Abdelrahman Ismail (ismail9k, https://ismail9k.com)?"
/></template>
<template #utilities><I9kLanguageSwitcher label="ุงูุนุฑุจูุฉ" code="ar" href="#ar" /></template>
</I9kFooter>
</div>Tagline and social links โ
vue
<div style="position: relative; border: 1px solid var(--border-color); border-radius: var(--radius-md);">
<I9kFooter
tagline="Built with the 9k design system."
:social-links="[
{ name: 'GitHub', url: 'https://github.com/ismail9k', icon: 'github' },
{ name: 'Mail', url: 'mailto:hello@ismail9k.com', icon: 'mail' },
]"
/>
</div>Custom footer content (default slot) โ
vue
<div style="position: relative; border: 1px solid var(--border-color); border-radius: var(--radius-md);">
<I9kFooter :social-links="[{ name: 'GitHub', url: 'https://github.com/ismail9k', icon: 'github' }]">
<p style="margin: 0; font-size: 0.85rem;">ยฉ 2026 Ismail9k. All rights reserved.</p>
</I9kFooter>
</div>Watch out โ
- The layout switches on
columns.lengthor a filledbrandslot โ pass neither and you get the centred stack, even if you setcopyright(which only renders in the multi-column brand block). - Only site-relative hrefs (a single leading "/") are handed to
linkComponent;https:,mailto:,tel:and protocol-relative//hostlinks always render plain anchors. external: trueaddstarget="_blank",rel="noopener"and an aria-hidden arrow. Do not set it onmailto:links.- The default slot fully replaces the tagline paragraph rather than appending to it.
- The social row only renders when
socialLinksis non-empty. I9kSocialLink is not exported โ inline its shape. - Both layouts render their content inside an I9kContainer, so the footer lines up with the header and the page column on its own; do not wrap it in another container.
API โ
Props โ
| Prop | Type | Default | Required |
|---|---|---|---|
tagline | string | null | null | no |
socialLinks | I9kSocialLink[] | () => [] | no |
socialLabels | boolean | false | no |
followLabel | (platform: string) => string | undefined | no |
columns | I9kFooterColumn[] | () => [] | no |
copyright | string | null | null | no |
brandHref | string | '/' | no |
brandLabel | string | 'Home' | no |
navLabel | string | 'Footer' | no |
linkComponent | string | object | null | null | no |
Emits โ
| Event | Payload |
|---|---|
socialClick | [item: I9kSocialLink, event: MouseEvent] |
navigate | [link: I9kFooterLink, event: MouseEvent] |
Slots โ
branddefaultextrasocial-iconutilities
Types โ
ts
export interface I9kFooterColumn {
id: string;
title: string;
links: I9kFooterLink[];
}
export interface I9kFooterLink {
id: string;
label: string;
/**
* Site-relative (`/talks`) hrefs go through the footer's `linkComponent`;
* anything else (`https:`, `mailto:`, protocol-relative `//host`) always
* renders a plain anchor.
*/
href: string;
/** Opens in a new tab and shows a direction-aware arrow. */
external?: boolean;
/** Emphasised, for the one destination a column should lead with. */
featured?: boolean;
/** Decorative prefix such as an emoji; hidden from assistive technology. */
emoji?: string;
}Agent prompt โ
Paste this into an agent to have it use the component correctly. It is self-contained.
text
Use I9kFooter from @9klabs/design as a page's <footer>.
import { I9kFooter, type I9kFooterColumn } from '@9klabs/design';
It has two layouts, chosen by what you pass:
- Centred (default): social links, then the tagline, then the utilities slot, stacked and centred. Suits a narrow page such as a link-in-bio.
- Multi-column: used as soon as `columns` is non-empty or the `brand` slot is filled. A brand block (brand, tagline, copyright) sits beside the link columns; social links and the utilities slot share a bottom bar under a divider. The grid has one track per column, up to four across; more wrap onto another row. Columns stack under the brand, two across, at 768px and below.
Props:
- tagline?: string | null (default null) โ plain text; replaced by the default slot when that is used.
- socialLinks?: I9kSocialLink[] (default []) โ rendered via I9kSocialLinks; { name: string; url: string; label?: string; icon?: I9kIconName }. That type is not exported โ inline the shape.
- socialLabels?: boolean (default false) โ show text labels next to each social icon.
- followLabel?: (platform: string) => string โ accessible name for each social link, forwarded to I9kSocialLinks (its default is "Follow on {platform}"). Pass a translated function for non-English pages.
- columns?: I9kFooterColumn[] (default []) โ { id: string; title: string; links: I9kFooterLink[] }. A link is { id: string; label: string; href: string; external?: boolean; featured?: boolean; emoji?: string }.
- copyright?: string | null (default null) โ small line under the tagline in the brand block.
- brandHref?: string (default '/') and brandLabel?: string (default 'Home') โ target and accessible name of the link wrapping the brand slot.
- navLabel?: string (default 'Footer') โ aria-label of the columns' <nav>.
- linkComponent?: string | object | null (default null) โ e.g. RouterLink or NuxtLink. Receives `to` for the brand and for site-relative links only.
Emits:
- socialClick โ [item: I9kSocialLink, event: MouseEvent]
- navigate โ [link: I9kFooterLink, event: MouseEvent], for any column link.
Slots:
- brand โ the wordmark or logo; wrapped in a link to brandHref. Filling it alone switches to the multi-column layout.
- default โ replaces the tagline paragraph.
- extra โ a row of its own under a divider, between the columns and the bottom bar (after the tagline when centred): I9kAskAi.
- utilities โ end of the bottom bar (or after the tagline when centred): a language switcher, a theme switcher, a markdown link.
- social-icon โ forwarded to I9kSocialLinks' icon slot; receives item.
IMPORTANT: only site-relative hrefs (a single leading "/") go through linkComponent. https:, mailto:, tel: and protocol-relative "//host" links always render a plain <a>, so a router never tries to resolve them.
IMPORTANT: external: true opens the link in a new tab with rel="noopener" and adds a decorative arrow that mirrors in RTL. Leave it off for mailto: links.
IMPORTANT: column headings are <h2>. Column titles and link labels are rendered as given โ translate them before passing.
Usage:
<I9kFooter
:columns="[
{ id: 'explore', title: 'Explore', links: [{ id: 'blog', label: 'Blog', href: '/blog' }] },
{ id: 'more', title: 'More from me', links: [{ id: 'school', label: '9k School', href: 'https://9k.school', external: true, featured: true, emoji: '๐' }] },
]"
tagline="Built with the 9k design system."
copyright="ยฉ 2026 Ismail9k"
:social-links="[{ name: 'GitHub', url: 'https://github.com/ismail9k', icon: 'github' }]"
:link-component="RouterLink"
@navigate="onNavigate"
>
<template #brand><I9kBrandWordmark /></template>
<template #utilities><I9kLanguageSwitcher label="ุงูุนุฑุจูุฉ" code="ar" href="/ar" /></template>
</I9kFooter>