| Summary | Custom Header Links allows you to easily add custom text-based links to the header. | |
| Preview | Preview on Discourse Theme Creator | |
| Repository Link | GitHub - discourse/discourse-custom-header-links · GitHub | |
| New to Discourse Themes? | Beginner’s guide to using Discourse Themes |
Install this theme component
Features
Desktop
Mobile
(due to very limited space, adding more than one link on mobile is not recommended)
Settings
| Setting | Description |
|---|---|
custom_header_links |
The structured list of links to display in the header. Each link is configured through a form with individual fields (see below). |
links_position |
Controls whether links appear on the right (default) or left side of the header near the logo. When set to left, all links are automatically hidden on topic pages to make room for the topic title — regardless of individual link hide_on_scroll settings. |
Adding Links
Links are configured through a structured form in the theme component settings. Click Add to add a new link. Each link has the following fields:
| Field | Required | Description |
|---|---|---|
| Text |
|
The visible label for the link. Max 100 characters. Also determines the CSS class applied to the link (see CSS Customisation below). |
| Title |
|
The tooltip text shown when hovering over the link. Max 1000 characters. |
| URL |
|
The URL the link points to. Can be a relative path (e.g. /faq) or a full URL. Max 2048 characters. |
| View |
|
Controls which device the link appears on. If left unset, the link shows on all devices (same as vdm). See values below. |
| Target |
|
Controls how the link opens. If left unset, defaults to opening in a new tab (same as blank). See values below. |
| Hide on scroll |
|
Controls whether the link hides when the topic title becomes visible in the header on topic pages. Defaults to keep. Only applies when links_position is set to right — see note below. See values below. |
| Locale |
|
If set, the link is only shown when the site’s page language matches this value. Leave blank to show the link on all locales. See details below. |
View values:
| Value | Behaviour |
|---|---|
vdm |
Visible on both desktop and mobile |
vdo |
Visible on desktop only |
vmo |
Visible on mobile only |
| (unset) | Same as vdm — visible on all devices |
Target values:
| Value | Behaviour |
|---|---|
blank |
Opens in a new tab |
self |
Opens in the same tab |
| (unset) | Defaults to opening in a new tab (same as blank) |
Hide on scroll values:
| Value | Behaviour |
|---|---|
keep |
Link stays visible even when the topic title is shown in the header (default) |
remove |
Link hides when the topic title becomes visible on topic pages |
![]()
hide_on_scrollonly applies whenlinks_positionisright. Whenlinks_positionisleft, all links are hidden together on topic pages regardless of their individualhide_on_scrollsetting.
Here’s an example of hide_on_scroll in action (with links_position set to right):
Most Liked and Privacy are set to keep, so they remain visible when the title expands. The other links are set to remove, so they hide when the title becomes visible. This behaviour only affects topic pages.
Locale Filtering
The Locale field allows you to show a link only when the site is set to a specific language. This is useful for multilingual communities that want different header links per language.
- Set the field to a locale code such as
en,de,fr,zh_CN, etc. - The match is case-insensitive, and both
-and_separators are treated identically — soen-US,en_US, anden_usall match equally. - If the locale field is left blank, the link shows on all locales. This is the recommended setting for most single-language sites.
- A CSS class
headerLink--{locale}is also added to the link element, which can be used for additional CSS targeting.
Common issue: If your links are not appearing, check whether you have accidentally set a
localevalue that does not match your site’s configured language. Leaving the locale field blank is safe and will always show the link.
CSS Customisation
Each link automatically receives a CSS class derived from its Text value: spaces are replaced with hyphens, the text is lowercased, and -custom-header-links is appended.
For example:
- A link with text
Privacygets the classprivacy-custom-header-links - A link with text
Visit Shopgets the classvisit-shop-custom-header-links
Style all header links:
.custom-header-links .headerLink a {
font-size: var(--font-up-1);
color: var(--header_primary);
}
Style a specific link (e.g. a link with text “Privacy”):
.custom-header-links .headerLink.privacy-custom-header-links a {
color: var(--tertiary);
}
.custom-header-links .headerLink.privacy-custom-header-links a:hover {
color: var(--tertiary-high);
}
Show or hide a link based on login state:
Discourse adds an anon class to the <html> tag for logged-out users. You can use this to conditionally show or hide links:
/* Hide "Dashboard" from logged-out users */
html.anon .dashboard-custom-header-links {
display: none;
}
/* Hide "Sign Up" from logged-in users */
html:not(.anon) .sign-up-custom-header-links {
display: none;
}
CSS
display: noneis a visual-only hiding mechanism. The link’s HTML is still present in the page source. Do not use this to protect sensitive or access-controlled URLs.
Reorder links with CSS (using flexbox order):
.custom-header-links li {
&:nth-child(1) { order: 3; }
&:nth-child(2) { order: 1; }
&:nth-child(3) { order: 2; }
}
Use the /my path for user-specific links, to avoid hardcoding a username:
/my/messages → the current user's inbox
/my/activity → the current user's activity
Hosted by us? Theme components are available to use on our Pro, Business, and Enterprise plans.
Changelog highlights:
- The
custom_header_linkssetting was migrated from a comma-delimited list format to a structuredtype: objectsform UI. If you previously configured links using the old comma-separated text input, the migration should have preserved your data automatically
Last edited by @Moin 2026-03-23T22:46:59Z
Last checked by @MarkDoerr 2026-03-23T22:39:09Z
Check document
Perform check on document:
