Menu
A menu: a row of text links, such as a footer's Contact us, Accessibility and Privacy, a gap apart and placed left, centred or right — centred on a phone. Its defaults come from menu in lib/menu.ts, and resolveMenu checks the props.
Examples
Menu on a dark footer
The menu in white on the grey, blue and red families’ darkest shades.
77.0 KB built. Open the built email (opens in a new tab)
const nswGovernment = [
{ network: 'facebook', href: 'https://www.facebook.com/NSWGovernment' },
{ network: 'x', href: 'https://x.com/NSWGovernment' },
{ network: 'youtube', href: 'https://www.youtube.com/user/nswgovernment' },
{ network: 'linkedin', href: 'https://www.linkedin.com/company/nswgovernment' },
{ network: 'instagram', href: 'https://www.instagram.com/nswgov' },
] as const
const nswFooterLinks = [
{ href: 'https://www.nsw.gov.au', label: 'Contact us' },
{
href: 'https://www.nsw.gov.au/nsw-government/about-website/accessibility-statement',
label: 'Accessibility',
},
{ href: 'https://www.nsw.gov.au/nsw-government/about-website/copyright', label: 'Copyright' },
{ href: 'https://www.nsw.gov.au/nsw-government/about-website/disclaimer', label: 'Disclaimer' },
{
href: 'https://www.nsw.gov.au/nsw-government/about-website/privacy-statement',
label: 'Privacy',
},
] as const
function Footer({
background,
color,
social,
logo,
}: {
/** The footer's fill. */
background: ColorValue
/** Its text and links. */
color: ColorValue
/** Its icons' tone. */
social: SocialTone
/** Its logo's tone. */
logo: LogoTone
}) {
const band = (
<NswColumns background={background} padding={false}>
<NswColumn>
<NswSpacer height={32} />
</NswColumn>
</NswColumns>
)
return (
<>
{band}
<NswColumns background={background}>
<NswColumn>
<NswSocial
links={nswGovernment}
tone={social}
size={28}
gap={16}
align='left'
mobileClass='mobile-left'
/>
<NswSpacer height={48} />
<NswText type='body-sm' color={color}>
McKell Building, 2-24 Rawson Place, Sydney NSW 2000
</NswText>
<NswSpacer height={8} />
<NswText type='body-sm' color={color}>
Copyright © 2026 NSW Department of Customer Service, All rights reserved.
</NswText>
<NswSpacer height={48} />
<NswMenu links={nswFooterLinks} type='body-sm' color={color} align='left' />
<NswSpacer height={48} />
<NswText type='body-sm' color={color}>
This message was sent to <strong>[name@domain.com]</strong>. If you don't want to
receive these emails from NSW Department of Customer Service in the future, you can{' '}
<NswLink href='https://example.com' color={color}>
unsubscribe
</NswLink>
.
</NswText>
<NswSpacer height={32} />
<NswLogo
tone={logo}
width={56}
href='https://www.digital.nsw.gov.au'
align='left'
mobileClass='mobile-left'
/>
</NswColumn>
</NswColumns>
{band}
</>
)
}
function FooterPage({
title,
themes,
}: {
title: string
themes: ReadonlyArray<{
key: string
background: ColorValue
color: ColorValue
social: SocialTone
logo: LogoTone
}>
}) {
return (
<NswLayout title={title}>
{themes.map((theme) => (
<Fragment key={theme.key}>
<Footer
background={theme.background}
color={theme.color}
social={theme.social}
logo={theme.logo}
/>
<NswColumns background='grey-100' padding={false}>
<NswColumn>
<NswSpacer height={24} />
</NswColumn>
</NswColumns>
</Fragment>
))}
</NswLayout>
)
}
const themes = [
{
key: 'grey',
background: 'grey-800',
color: 'white',
social: 'white',
logo: 'reversed',
},
{
key: 'primary',
background: 'primary-800',
color: 'white',
social: 'white',
logo: 'reversed',
},
{
key: 'accent',
background: 'accent-800',
color: 'white',
social: 'white',
logo: 'reversed',
},
] as const;
<FooterPage title='Menu on a dark footer' themes={themes} /><FooterPage> is a demo helper shown inline above, not part of the package: copy it with the example, or swap in your own.
Menu on a bright footer
The menu in white on the grey, blue and red families’ 600 shades.
77.0 KB built. Open the built email (opens in a new tab)
const nswGovernment = [
{ network: 'facebook', href: 'https://www.facebook.com/NSWGovernment' },
{ network: 'x', href: 'https://x.com/NSWGovernment' },
{ network: 'youtube', href: 'https://www.youtube.com/user/nswgovernment' },
{ network: 'linkedin', href: 'https://www.linkedin.com/company/nswgovernment' },
{ network: 'instagram', href: 'https://www.instagram.com/nswgov' },
] as const
const nswFooterLinks = [
{ href: 'https://www.nsw.gov.au', label: 'Contact us' },
{
href: 'https://www.nsw.gov.au/nsw-government/about-website/accessibility-statement',
label: 'Accessibility',
},
{ href: 'https://www.nsw.gov.au/nsw-government/about-website/copyright', label: 'Copyright' },
{ href: 'https://www.nsw.gov.au/nsw-government/about-website/disclaimer', label: 'Disclaimer' },
{
href: 'https://www.nsw.gov.au/nsw-government/about-website/privacy-statement',
label: 'Privacy',
},
] as const
function Footer({
background,
color,
social,
logo,
}: {
/** The footer's fill. */
background: ColorValue
/** Its text and links. */
color: ColorValue
/** Its icons' tone. */
social: SocialTone
/** Its logo's tone. */
logo: LogoTone
}) {
const band = (
<NswColumns background={background} padding={false}>
<NswColumn>
<NswSpacer height={32} />
</NswColumn>
</NswColumns>
)
return (
<>
{band}
<NswColumns background={background}>
<NswColumn>
<NswSocial
links={nswGovernment}
tone={social}
size={28}
gap={16}
align='left'
mobileClass='mobile-left'
/>
<NswSpacer height={48} />
<NswText type='body-sm' color={color}>
McKell Building, 2-24 Rawson Place, Sydney NSW 2000
</NswText>
<NswSpacer height={8} />
<NswText type='body-sm' color={color}>
Copyright © 2026 NSW Department of Customer Service, All rights reserved.
</NswText>
<NswSpacer height={48} />
<NswMenu links={nswFooterLinks} type='body-sm' color={color} align='left' />
<NswSpacer height={48} />
<NswText type='body-sm' color={color}>
This message was sent to <strong>[name@domain.com]</strong>. If you don't want to
receive these emails from NSW Department of Customer Service in the future, you can{' '}
<NswLink href='https://example.com' color={color}>
unsubscribe
</NswLink>
.
</NswText>
<NswSpacer height={32} />
<NswLogo
tone={logo}
width={56}
href='https://www.digital.nsw.gov.au'
align='left'
mobileClass='mobile-left'
/>
</NswColumn>
</NswColumns>
{band}
</>
)
}
function FooterPage({
title,
themes,
}: {
title: string
themes: ReadonlyArray<{
key: string
background: ColorValue
color: ColorValue
social: SocialTone
logo: LogoTone
}>
}) {
return (
<NswLayout title={title}>
{themes.map((theme) => (
<Fragment key={theme.key}>
<Footer
background={theme.background}
color={theme.color}
social={theme.social}
logo={theme.logo}
/>
<NswColumns background='grey-100' padding={false}>
<NswColumn>
<NswSpacer height={24} />
</NswColumn>
</NswColumns>
</Fragment>
))}
</NswLayout>
)
}
const themes = [
{
key: 'grey',
background: 'grey-600',
color: 'white',
social: 'white',
logo: 'reversed',
},
{
key: 'primary',
background: 'primary-600',
color: 'white',
social: 'white',
logo: 'reversed',
},
{
key: 'accent',
background: 'accent-600',
color: 'white',
social: 'white',
logo: 'reversed',
},
] as const;
<FooterPage title='Menu on a bright footer' themes={themes} /><FooterPage> is a demo helper shown inline above, not part of the package: copy it with the example, or swap in your own.
Menu on a pale footer
The menu on the grey, blue and red families’ palest shades, in each family’s darkest.
77.3 KB built. Open the built email (opens in a new tab)
const nswGovernment = [
{ network: 'facebook', href: 'https://www.facebook.com/NSWGovernment' },
{ network: 'x', href: 'https://x.com/NSWGovernment' },
{ network: 'youtube', href: 'https://www.youtube.com/user/nswgovernment' },
{ network: 'linkedin', href: 'https://www.linkedin.com/company/nswgovernment' },
{ network: 'instagram', href: 'https://www.instagram.com/nswgov' },
] as const
const nswFooterLinks = [
{ href: 'https://www.nsw.gov.au', label: 'Contact us' },
{
href: 'https://www.nsw.gov.au/nsw-government/about-website/accessibility-statement',
label: 'Accessibility',
},
{ href: 'https://www.nsw.gov.au/nsw-government/about-website/copyright', label: 'Copyright' },
{ href: 'https://www.nsw.gov.au/nsw-government/about-website/disclaimer', label: 'Disclaimer' },
{
href: 'https://www.nsw.gov.au/nsw-government/about-website/privacy-statement',
label: 'Privacy',
},
] as const
function Footer({
background,
color,
social,
logo,
}: {
/** The footer's fill. */
background: ColorValue
/** Its text and links. */
color: ColorValue
/** Its icons' tone. */
social: SocialTone
/** Its logo's tone. */
logo: LogoTone
}) {
const band = (
<NswColumns background={background} padding={false}>
<NswColumn>
<NswSpacer height={32} />
</NswColumn>
</NswColumns>
)
return (
<>
{band}
<NswColumns background={background}>
<NswColumn>
<NswSocial
links={nswGovernment}
tone={social}
size={28}
gap={16}
align='left'
mobileClass='mobile-left'
/>
<NswSpacer height={48} />
<NswText type='body-sm' color={color}>
McKell Building, 2-24 Rawson Place, Sydney NSW 2000
</NswText>
<NswSpacer height={8} />
<NswText type='body-sm' color={color}>
Copyright © 2026 NSW Department of Customer Service, All rights reserved.
</NswText>
<NswSpacer height={48} />
<NswMenu links={nswFooterLinks} type='body-sm' color={color} align='left' />
<NswSpacer height={48} />
<NswText type='body-sm' color={color}>
This message was sent to <strong>[name@domain.com]</strong>. If you don't want to
receive these emails from NSW Department of Customer Service in the future, you can{' '}
<NswLink href='https://example.com' color={color}>
unsubscribe
</NswLink>
.
</NswText>
<NswSpacer height={32} />
<NswLogo
tone={logo}
width={56}
href='https://www.digital.nsw.gov.au'
align='left'
mobileClass='mobile-left'
/>
</NswColumn>
</NswColumns>
{band}
</>
)
}
function FooterPage({
title,
themes,
}: {
title: string
themes: ReadonlyArray<{
key: string
background: ColorValue
color: ColorValue
social: SocialTone
logo: LogoTone
}>
}) {
return (
<NswLayout title={title}>
{themes.map((theme) => (
<Fragment key={theme.key}>
<Footer
background={theme.background}
color={theme.color}
social={theme.social}
logo={theme.logo}
/>
<NswColumns background='grey-100' padding={false}>
<NswColumn>
<NswSpacer height={24} />
</NswColumn>
</NswColumns>
</Fragment>
))}
</NswLayout>
)
}
const themes = [
{
key: 'grey',
background: 'grey-200',
color: 'grey-800',
social: 'nsw-grey-800',
logo: 'primary',
},
{
key: 'primary',
background: 'primary-200',
color: 'primary-800',
social: 'nsw-blue-800',
logo: 'primary',
},
{
key: 'accent',
background: 'accent-200',
color: 'accent-800',
social: 'nsw-red-800',
logo: 'primary',
},
] as const;
<FooterPage title='Menu on a pale footer' themes={themes} /><FooterPage> is a demo helper shown inline above, not part of the package: copy it with the example, or swap in your own.
Menu
The footer links as a menu, in a grey, a blue and a red footer on white.
77.3 KB built. Open the built email (opens in a new tab)
const nswGovernment = [
{ network: 'facebook', href: 'https://www.facebook.com/NSWGovernment' },
{ network: 'x', href: 'https://x.com/NSWGovernment' },
{ network: 'youtube', href: 'https://www.youtube.com/user/nswgovernment' },
{ network: 'linkedin', href: 'https://www.linkedin.com/company/nswgovernment' },
{ network: 'instagram', href: 'https://www.instagram.com/nswgov' },
] as const
const nswFooterLinks = [
{ href: 'https://www.nsw.gov.au', label: 'Contact us' },
{
href: 'https://www.nsw.gov.au/nsw-government/about-website/accessibility-statement',
label: 'Accessibility',
},
{ href: 'https://www.nsw.gov.au/nsw-government/about-website/copyright', label: 'Copyright' },
{ href: 'https://www.nsw.gov.au/nsw-government/about-website/disclaimer', label: 'Disclaimer' },
{
href: 'https://www.nsw.gov.au/nsw-government/about-website/privacy-statement',
label: 'Privacy',
},
] as const
function Footer({
background,
color,
social,
logo,
}: {
/** The footer's fill. */
background: ColorValue
/** Its text and links. */
color: ColorValue
/** Its icons' tone. */
social: SocialTone
/** Its logo's tone. */
logo: LogoTone
}) {
const band = (
<NswColumns background={background} padding={false}>
<NswColumn>
<NswSpacer height={32} />
</NswColumn>
</NswColumns>
)
return (
<>
{band}
<NswColumns background={background}>
<NswColumn>
<NswSocial
links={nswGovernment}
tone={social}
size={28}
gap={16}
align='left'
mobileClass='mobile-left'
/>
<NswSpacer height={48} />
<NswText type='body-sm' color={color}>
McKell Building, 2-24 Rawson Place, Sydney NSW 2000
</NswText>
<NswSpacer height={8} />
<NswText type='body-sm' color={color}>
Copyright © 2026 NSW Department of Customer Service, All rights reserved.
</NswText>
<NswSpacer height={48} />
<NswMenu links={nswFooterLinks} type='body-sm' color={color} align='left' />
<NswSpacer height={48} />
<NswText type='body-sm' color={color}>
This message was sent to <strong>[name@domain.com]</strong>. If you don't want to
receive these emails from NSW Department of Customer Service in the future, you can{' '}
<NswLink href='https://example.com' color={color}>
unsubscribe
</NswLink>
.
</NswText>
<NswSpacer height={32} />
<NswLogo
tone={logo}
width={56}
href='https://www.digital.nsw.gov.au'
align='left'
mobileClass='mobile-left'
/>
</NswColumn>
</NswColumns>
{band}
</>
)
}
function FooterPage({
title,
themes,
}: {
title: string
themes: ReadonlyArray<{
key: string
background: ColorValue
color: ColorValue
social: SocialTone
logo: LogoTone
}>
}) {
return (
<NswLayout title={title}>
{themes.map((theme) => (
<Fragment key={theme.key}>
<Footer
background={theme.background}
color={theme.color}
social={theme.social}
logo={theme.logo}
/>
<NswColumns background='grey-100' padding={false}>
<NswColumn>
<NswSpacer height={24} />
</NswColumn>
</NswColumns>
</Fragment>
))}
</NswLayout>
)
}
const themes = [
{
key: 'grey',
background: 'white',
color: 'grey-800',
social: 'nsw-grey-800',
logo: 'primary',
},
{
key: 'primary',
background: 'white',
color: 'primary-800',
social: 'nsw-blue-800',
logo: 'primary',
},
{
key: 'accent',
background: 'white',
color: 'accent-800',
social: 'nsw-red-800',
logo: 'primary',
},
] as const;
<FooterPage title='Menu' themes={themes} /><FooterPage> is a demo helper shown inline above, not part of the package: copy it with the example, or swap in your own.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
mobileClass | string | mobile-center, as the legacy's; give '' to keep the row's own alignment | Mobile utility class(es) on the links' table, for a document's own @media rule: mobile-center centres the links on a phone, mobile-left keeps them at the left, and a row the phone wraps lines up the same way. Default mobile-center, as the legacy's; give '' to keep the row's own alignment. |
devices | Devices | — | Which devices show the menu: left out, every device; desktop hides it on a phone (hide-on-mobile); mobile shows it on a phone only — hidden inline everywhere else, shown by the document's .show-on-mobile rule, and kept from Windows Outlook by mso-hide: all and the <!--[if !mso]> comments around it (see src/lib/devices.ts), as <NswSocial devices> is. |
className | string | — | Class(es) added to every link, beside its hover tint, for a document's own stylesheet. |
hover | string | the colour's | The hover class each link draws in place of the tint its colour takes, or '' for none; a callout hands its links its own tint through it. Default the colour's. |
defaults | TextDefaults | — | The email's text settings (<NswLayout text>), handed down by the layout to every text-bearing primitive beneath it; the menu's own props win. Its links take the email's link colour and face from it, as a link does. |
links (required) | readonly MenuLink[] | — | The links, in the order they are drawn, each { href, label }: the address it goes to and the text it shows. At least one is required. |
type | TypeScaleName | body | The links' step of the type scale, which sets their size and line height (body, body-sm, …); the links are bold, as every link is. Default body. |
color | ColorValue | the email's link colour (<NswLayout text>), else the link's primary blue | The links' colour: a theme colour name or a hex literal; their hover tint follows it, as every link's does (a colour family's 800 its own at 10%, white white at 10%). Default the email's link colour (<NswLayout text>), else the link's primary blue. |
gap | number | 16 | The space between two links in whole px. Default 16. |
align | Align | center | Where the links sit in their row: left, center or right. Default center. |