From d6a463d6f9b169a30db787f92738c159a2b63865 Mon Sep 17 00:00:00 2001
From: Luffy <52o@qq52o.cn>
Date: Mon, 16 Mar 2026 11:38:49 +0800
Subject: [PATCH 1/4] feat: add pageTitleFormatter option for customizable
document title
---
docs/configuration.md | 18 ++++++++++++++++++
src/core/config.js | 1 +
src/core/event/index.js | 12 ++++++++++--
3 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/docs/configuration.md b/docs/configuration.md
index d9cdfd05b1..68a8cfcd45 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -275,6 +275,24 @@ window.$docsify = {
};
```
+## pageTitleFormatter
+
+- Type: `Function | null`
+- Default: `null`
+
+Optional function to customize how the site `name` is used when composing the document title. If provided, Docsify will call this function with the configured `name` (which may contain HTML) and use the returned string as the title portion for the site name — Docsify will not automatically strip HTML or otherwise modify the value. If not provided, Docsify falls back to the default behavior of stripping HTML tags from `name`.
+
+Basic example — strip HTML and trim (equivalent to Docsify's default behavior):
+
+```js
+window.$docsify = {
+ name: 'My Site',
+ pageTitleFormatter(name) {
+ return name ? name.replace(/<[^>]+>/g, '').trim() : '';
+ },
+};
+```
+
## hideSidebar
- Type : `Boolean`
diff --git a/src/core/config.js b/src/core/config.js
index f433b33d06..b2e2fdb9e2 100644
--- a/src/core/config.js
+++ b/src/core/config.js
@@ -27,6 +27,7 @@ const defaultDocsifyConfig = () => ({
fallbackLanguages: /** @type {null | string[]} */ (null),
fallbackDefaultLanguage: '',
formatUpdated: /** @type {string | ((updatedAt: string) => string)} */ (''),
+ pageTitleFormatter: /** @type {null | ((name: string) => string)} */ (null),
/** For the frontmatter plugin. */
frontMatter: /** @type {Record | null} */ (null),
hideSidebar: false,
diff --git a/src/core/event/index.js b/src/core/event/index.js
index 1fd7abce9b..8880195b88 100644
--- a/src/core/event/index.js
+++ b/src/core/event/index.js
@@ -323,13 +323,21 @@ export function Events(Base) {
* @void
*/
onRender() {
- const { name } = this.config;
+ const { name, pageTitleFormatter } = this.config;
const currentPath = this.router.toURL(this.router.getCurrentPath());
const currentSection = dom
.find(`.sidebar a[href='${currentPath}']`)
?.getAttribute('title');
- const plainName = name ? name.replace(/<[^>]+>/g, '').trim() : name;
+ // If a pageTitleFormatter is provided, let the user format the name
+ // (no automatic HTML stripping). Otherwise, default to stripping
+ // HTML tags from the configured name.
+ const plainName =
+ typeof pageTitleFormatter === 'function'
+ ? pageTitleFormatter(name)
+ : name
+ ? name.replace(/<[^>]+>/g, '').trim()
+ : name;
const currentTitle = plainName
? currentSection
? `${currentSection} - ${plainName}`
From d50e476d717209b09cb3a31417cd8115c64bc630 Mon Sep 17 00:00:00 2001
From: Luffy <52o@qq52o.cn>
Date: Mon, 16 Mar 2026 11:39:31 +0800
Subject: [PATCH 2/4] fix: adjust indentation for page title formatting logic
---
src/core/event/index.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/core/event/index.js b/src/core/event/index.js
index 8880195b88..040c5b7148 100644
--- a/src/core/event/index.js
+++ b/src/core/event/index.js
@@ -336,8 +336,8 @@ export function Events(Base) {
typeof pageTitleFormatter === 'function'
? pageTitleFormatter(name)
: name
- ? name.replace(/<[^>]+>/g, '').trim()
- : name;
+ ? name.replace(/<[^>]+>/g, '').trim()
+ : name;
const currentTitle = plainName
? currentSection
? `${currentSection} - ${plainName}`
From 836488a23b48455f28e76fcb45ef4412ee93ca50 Mon Sep 17 00:00:00 2001
From: Luffy <52o@qq52o.cn>
Date: Mon, 16 Mar 2026 11:53:32 +0800
Subject: [PATCH 3/4] fix: ensure pageTitleFormatter is called with a valid
string name
---
src/core/event/index.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/core/event/index.js b/src/core/event/index.js
index 040c5b7148..e9c446cee0 100644
--- a/src/core/event/index.js
+++ b/src/core/event/index.js
@@ -333,7 +333,7 @@ export function Events(Base) {
// (no automatic HTML stripping). Otherwise, default to stripping
// HTML tags from the configured name.
const plainName =
- typeof pageTitleFormatter === 'function'
+ typeof pageTitleFormatter === 'function' && typeof name === 'string'
? pageTitleFormatter(name)
: name
? name.replace(/<[^>]+>/g, '').trim()
From 44768053d7da84c10c92432a5e4660eed8514cd4 Mon Sep 17 00:00:00 2001
From: Luffy <52o@qq52o.cn>
Date: Mon, 16 Mar 2026 12:02:04 +0800
Subject: [PATCH 4/4] docs: update pageTitleFormatter type to reflect required
function
---
docs/configuration.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/configuration.md b/docs/configuration.md
index 68a8cfcd45..7b61752984 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -277,7 +277,7 @@ window.$docsify = {
## pageTitleFormatter
-- Type: `Function | null`
+- Type: `Function`
- Default: `null`
Optional function to customize how the site `name` is used when composing the document title. If provided, Docsify will call this function with the configured `name` (which may contain HTML) and use the returned string as the title portion for the site name — Docsify will not automatically strip HTML or otherwise modify the value. If not provided, Docsify falls back to the default behavior of stripping HTML tags from `name`.
@@ -474,7 +474,7 @@ window.$docsify = {
## name
-- Type: `Boolean | String`
+- Type: `Boolean|String`
Website name as it appears in the sidebar.