Note

This is part of the Advanced Customizations.

The default ordering methods sort the notes alphanumerically. For a custom order, one has to include a numerical prefix to each title, making it unnecessarily long. Instead, we can use an extra attribute in the front matter to implicitly define the order we want.

Update: Folders deserve to be sorted as well. There are two schemes for folder ordering:

  1. Place folders ahead of files as we used to do, then sort folders and files using frontmatter attributes folderOrder and noteOrder respectively.
  2. Treat folders the same as pages. That is, folderOrder will be compared with noteOrder when it comes to folder-page sorting.

We place all numbered objects ahead of the rest. Then sort the numbered items based on values in noteOrder and folderOrder. Those without an available value will fall back to the alphanumerical order.

Add noteOrder and folderOrder

To assign a number to a note, simply add a noteOrder attribute to its frontmatter. But which .md file should I put the folderOrder into?

Only the folderOrder in index.md inside that folder will be accessed. Based on the guide, it’s suggested to place an index.md under any folder. Here’s why it’s a good practice:

  1. You can overwrite the name of a folder using title in the frontmatter of index.md.
  2. Separate folderOrder and noteOrder so that note files will not have folder attributes in it.
  3. Allow further customization for folders, for example, Customizing Collapse Status.

Note

If you choose to hide a folder following the guides in Creating a Secret Garden, remember to also include an exclusive tag in the index.md.

To sum up, noteOrder defines the ranking of the note, and folderOrder defines the ranking of the parent folder among its sibling (notes and) folders.

Add frontmatter back

Note

After my upgrade on Mar 15, 2025, from my last upgrade on Jan 1, the type of node has been changed from FileNode in quartz/components/ExplorerNode.tsx, to FileTrieNode in quartz/util/fileTrie.ts.

There is no frontmatter attribute in the latest node structure. Thus, we can manually include frontmatter in ContentDetails and linkIndex.set() in quartz/plugins/emitters/contentIndex.tsx.

Not sure whether there are any drawbacks. Let me know if you have any comments.

Add our attribute frontmatter to the existing type ContentDetails, which defines node.data.

quartz/plugins/emitters/contentIndex.tsx
...
// mod: inherit definition of frontmatter
import { QuartzPluginData } from "../vfile"
 
export type ContentIndexMap = Map<FullSlug, ContentDetails>
export type ContentDetails = {
  slug: FullSlug
  filePath: FilePath
  title: string
  links: SimpleSlug[]
  tags: string[]
  content: string
  richContent?: string
  date?: Date
  description?: string
  // mod: add frontmatter
  frontmatter?: QuartzPluginData["frontmatter"]
}

Then set the value properly in linkIndex.set().

quartz/plugins/emitters/contentIndex.tsx
linkIndex.set(slug, {
  slug,
  filePath: file.data.filePath!,
  title: file.data.frontmatter?.title!,
  links: file.data.links ?? [],
  tags: file.data.frontmatter?.tags ?? [],
  content: file.data.text ?? "",
  richContent: opts?.rssFullHtml
    ? escapeHTML(toHtml(tree as Root, { allowDangerousHtml: true }))
    : undefined,
  date: date,
  description: file.data.description ?? "",
  // mod: add the original frontmatter as whole
  frontmatter: file.data.frontmatter,
})

Define sortFn

According to the tips, create the Explorer functions as follows. Comment out one of the methods to use another.

Method I is to comply with the sorting traditions in Quartz, where notes must come after folders. Method II is recommended as it provides full control over the order.

quartz/quartz.layout.ts
// mod: define Explorer functions
import { Options } from "./quartz/components/Explorer"
 
export const mapFn: Options["mapFn"] = (node) => {
  return node
}
export const filterFn: Options["filterFn"] = (node) => {
  return node.slugSegment !== "tags"
}
export const sortFn: Options["sortFn"] = (a, b) => {
  // mod: sort folders and files based on folderOrder and noteOrder
  //      to find ways to retrieve folderOrder and noteOrder from frontmatter
  //      we now have to include frontmatter in ContentDetails and linkIndex.set()
 
  // extract order from frontmatter
  const orderA = a.isFolder
    ? a.data?.frontmatter?.folderOrder as number | undefined
    : a.data?.frontmatter?.noteOrder as number | undefined
  const orderB = b.isFolder
    ? b.data?.frontmatter?.folderOrder as number | undefined
    : b.data?.frontmatter?.noteOrder as number | undefined
 
  // method I: folders first, then files, sort folders and files separately
  // compare orderA and orderB, those undefined will be placed at the end
  if ((!a.isFolder && !b.isFolder) || (a.isFolder && b.isFolder)) {
    if (orderA !== undefined && orderB !== undefined) {
      // compare based on the order
      return orderA - orderB;
    } else if (orderA !== undefined) {
      // move B to the back
      return -1;
    } else if (orderB !== undefined) {
      // move A to the back
      return 1;
    } else {
      // fall back to alphabetical order
      return a.displayName.localeCompare(b.displayName);
    }
  }
  // keep folders in front
  if (!a.isFolder && b.isFolder) {
    return 1
  } else {
    return -1
  }
 
  // method II: sort folders together with files, treat folders as files
  // compare orderA and orderB, those undefined will be placed at the end
  if (orderA !== undefined && orderB !== undefined) {
    return orderA - orderB
  } else if (orderA !== undefined) {
    return -1
  } else if (orderB !== undefined) {
    return 1
  } else {
    return a.displayName.localeCompare(b.displayName)
  }
}

Then apply at wherever Explorer is included.

quartz/quartz.layout.ts
Component.Explorer({
  mapFn,
  filterFn,
  sortFn,
}),