Hiding frontmatter

There are certain pages that I use frontmatter, but I would like to hide it. One example case is custom decorations, I already see them on the page, I don’t want to look as frontmatter definitions.
Is there a way to hide or fold frontmatter?

2 Likes

This would be very useful, it would allow you to have a panel with metadata and present only those relevant to the display just below and formatted.

You can fold it (Outline: Fold) but this won’t persist. Feel free to create a GitHub issue for it with specifics on how you would like this to work.

Added GitHub Issue, more like an (enhancement).

3 Likes

As a workaround to fully hide it for some pages you can add the following combination of space-style and pageDecoration frontmatter:

Add style that allows to hide frontmatter on pages with css class no-frontmatter:

```space-style
.no-frontmatter .sb-frontmatter {
    display: none;
}
```

Then add cssClasses decoration to the pages where you want to hide it e.g. using frontmatter:

---
pageDecoration:
    cssClasses:
      - no-frontmatter
---

I use it myself for hiding it on prefixed pages, could probably also be done using object decorations for all pages with prefixes. Changing the frontmatter again requires commenting the style so it is really only a workaround and a proper solution would be preferred.

11 Likes

Not a perfect solve, but a great workaround!

I was looking for this too, and came up with a solution I thought might be worth sharing. I haven’t tested it across too many browsers yet, but it’s working for me. Uses just one bit of css in the space-style to hide the frontmatter block down to just the first line (showing that there is frontmatter) until you move the cursor into it to make edits.

.sb-frontmatter.sb-line-frontmatter-outside:has(+ .sb-frontmatter) ~ .sb-frontmatter {
    display:none
}
7 Likes

Thanks for this, it works great on Edge :slight_smile:

Is it possible with CSS to move the cursor position to below the frontmatter? On page load, the cursor goes to the first line (which contains frontmatter) but given we want it folded it’d be nice to place the cursor below the last line of frontmatter.

Edit: Looks like I might be able to use this solution.

I was just about to say, you can do something like this. But if Zef’s example works, then that is much cleaner! It leaves the cursor inside the front matter, but with a single arrow down you can get out of it.

Just because I was working on it anyway, if you still want to move your cursor below the front matter automagically.

event.listen {
  name = "editor:pageLoaded",
  run = function(e)
    local page = editor.getText()
    if not string.startsWith(page, "---") then
      print("🪅 no frontmatter")
      return
    end

    -- find the position of the closing dashes of the frontmatter
    local skipOpening = string.sub(page, 3)
    local posClosing = string.find(skipOpening, "%-%-%-")
    local posAfterFM = posClosing + 3 + 2 -- open (3) + closing (2) matter
    
    local pos = editor.getCursor()
    if (pos >= posAfterFM) then
      print("🪅 cursor is already past frontmatter: ", pos)
      return
    end
    
    print("🪅 moving cursor to:", posAfterFM)
    editor.moveCursor(posAfterFM)
  end
}
1 Like

So I’ve also come up with a solution to this that creates a command to hide the frontmatter and tags while using the vertical menu from Mr. Red.

First I should say I organize all of my notes by tags, which I put at the end of paragraphs and pages and everywhere – tags all over the place. So when I view notes, I like to hide the front matter and those tags so it’s visually clean with just the text I want to read. The code below is for both tags and frontmatter, but you can see they’re clearly separated, so if you only want to hide frontmatter, just delete the tags sections.

I’ll admit I’m not a programmer, so I’m not sure how elegant this solution is – it works well, though!

I first created a page in my library to input the space script:

silverbullet.registerCommand({name: "Toggle UI Elements"}, async () => {
  // Get the body element
  const body = document.body;
  
  // Toggle both classes
  body.classList.toggle("hide-tags");
  body.classList.toggle("hide-frontmatter");
  
  // Show notification
  await editor.flashNotification("UI elements visibility toggled");
});

In SETTINGS, add:

/* Styles for hidden elements */
body.hide-tags .sb-hashtag {
  display: none;
}

body.hide-frontmatter .sb-frontmatter {
  display: none;
}

Then in the space-config for the vertical menu settings, I added:

  • icon: eye
    command: “{[Toggle UI Elements]}”
    description: “Toggle UI visibility (tags & frontmatter)”

If you don’t want to add to the menu, you can just run it as a regular command.

1 Like

Pretty smart solution. I wonder if there’s going to be a way to still do that in v2, considering space-script will be removed.

@zef will there be a Lua DOM manipulation API? :innocent:

3 Likes

I came up with this for v2 and space-lua, to temporarily unhide the hidden frontmatter. I know it’s not the most elegant solution and it’s more like a hack, but it works for me.

If you have your frontmatter hidden with following:

[space-style]

.no-frontmatter .sb-frontmatter { display: none; }

I created this handy little command which does the following:

  • press “Ctrl-0” → checks if the page has a frontmatter (if first line is “—”) then add “:construction:” to the beginning of the line, disabling the frontmatter temporarily.
  • if you press “Ctrl-0” again → it will check if the first line ends with “—” then it will “enable” the frontmatter by changing the first line back from “:construction:—” to “—” . toggling the frontmatter on again.
  • if no frontmatter was found the info that the page has no frontmatter.

[space-lua]

function toggleFrontmatter()
  editor.moveCursor(0, true)
  local firstLine = editor.getCurrentLine()

    if firstLine.text == "---" then
            editor.insertAtCursor("🚧")
    else if firstLine.text:endsWith("---") then
            editor.replaceRange(firstLine.from, firstLine.to, "---")
    else editor.flashNotification("⚠️Page has no frontmatter!")  end
    end
end

command.define {
  name = "Show: Toggle Disabled Frontmatter",
  key  = "Ctrl-0",
  run  = function()
    toggleFrontmatter()
  end
}

go on, give it a try and tell me what you think!

Do you have a better solution to “unhiding/toggling” the hidden frontmatter?

here my script to toggle Frontmatter (Ctrl-Alt-f) for all pages or to auto-hide Frontmatter for a particular page by specifying

---
hide-frontmatter: true
---

in the corresponding Frontmatter section.

-- Toggle frontmatter visibility with auto-hide support
-- Auto-hides if page has hide-frontmatter: true in frontmatter

local styleId = 'hide-frontmatter-css'
local style = '.sb-frontmatter, .sb-line-frontmatter-outside, .sb-frontmatter-marker { display: none !important; }'

local function scrollToFrontmatter()
  local fm = js.window.document.querySelector('.sb-frontmatter, .sb-line-frontmatter-outside')
  if fm then
    fm.scrollIntoView({ behavior = 'smooth', block = 'start' })
  end
end

local function setVisibility(hidden)
  local el = js.window.document.getElementById(styleId)
  if hidden and not el then
    js.window.document.head.insertAdjacentHTML('beforeend', '<style id="' .. styleId .. '">' .. style .. '</style>')
  elseif not hidden and el then
    el.remove()
    js.window.setTimeout(scrollToFrontmatter, 50)
  end
end

local function pageHasHideFrontmatter()
  local pageName = editor.getCurrentPage()
  if not pageName then return false end
  
  local success, pageText = pcall(function() return space.readPage(pageName) end)
  if not success or not pageText then return false end
  
  -- Find frontmatter block boundaries
  local startPos = string.find(pageText, "^%-%-%-")
  if not startPos then return false end
  
  -- Find the end of frontmatter (second ---)
  local endPos = string.find(pageText, "[\r\n]+%-%-%-", startPos + 3)
  if not endPos then return false end
  
  -- Extract frontmatter content (between first --- and second ---)
  local fm = string.sub(pageText, startPos + 3, endPos - 1)
  fm = string.gsub(fm, "^%s*[\r\n]+", "")  -- Remove leading whitespace/newlines
  fm = string.gsub(fm, "[\r\n]+%s*$", "")  -- Remove trailing whitespace/newlines
  
  -- Check for hide-frontmatter: true (case-insensitive)
  return string.match(string.lower(fm), "hide%-frontmatter%s*:%s*true") ~= nil
end

function toggleFrontmatterVisibility()
  local isHidden = js.window.document.getElementById(styleId) ~= nil
  setVisibility(not isHidden)
  js.window.localStorage.setItem('frontmatterHidden', tostring(not isHidden))
end

local function updateVisibility()
  local shouldHide = pageHasHideFrontmatter() or 
                     js.window.localStorage.getItem('frontmatterHidden') == 'true'
  setVisibility(shouldHide)
end

command.define {
  name = "Toggle Frontmatter Visibility",
  key = "Ctrl-Alt-f",
  mac = "Cmd-Alt-f",
  run = toggleFrontmatterVisibility
}

local function delayedUpdate(delay)
  js.window.setTimeout(updateVisibility, delay or 100)
end

event.listen { name = 'editor:pageLoaded', run = function() delayedUpdate(100) end }
event.listen { name = 'editor:pageSaved', run = function() delayedUpdate(100) end }
event.listen { name = 'system:ready', run = function() delayedUpdate(200) end }
1 Like

What an interesting mix of space-lua / CSS / JS :exploding_head:

Instead of the regex searching and checking for a text match key-value pair (hide-frontmatter: true)
you could have simply used the index.extractFrontmatter() function, this return exactly the value “true” if inserted.

but other than that a nice implementaion :clap:
will definitely use it in the future :wink:
Thanks!

1 Like

Does anyone know how to override / break pages where front matter has been hidden? So I’ve added

cssClasses:
      - no-frontmatter

And now I want to replace with this script version, but because the frontmatter is hidden, I can’t change it…

Find the following space-style in your space and replace display:none; by display:block;

.no-frontmatter .sb-frontmatter {
    display: none;
}

Command System: Reload or Ctrl+Alt+r to take effect. Check.

Then, you can remove the space-style as well as the no-frontmatter from your pages, and switch to the space-lua from @inos-github modified by @Mr.Red.

You will find the same functionality as before by adding the hide-frontmatter: true or hide-frontmatter: false attribute (or nothing) in the frontmatter of your pages. Nb : this is not a custom class like no-frontmatter ; it’s an attribute.

In addition, you can switch the display mode on the fly with the keyboard shortcut defined in space-lua (if you are on Windows, I advise you to change the “.” with a letter).

Thank you! I actually was playing around with it and I just broke the “no-frontmatter” function in Config by deleting the ``` to put it in code. Then re-indexed and the frontmatter showed up. So then I swapped out the “no-frontmatter” with “hide-frontmatter: true” and then un-broke Config and voila!

Just for confirmation:

and then un-broke Config

→ you will no longer need to use : .no-frontmatter .sb-frontmatter {display: none;} because no-frontmatter class does’nt exist on your pages. So, you can delete it.

I swapped out the “no-frontmatter” with “hide-frontmatter: true”

yes but note no-frontmatter is a class (within pageDecoration:cssClasses:) and hide-frontmatter is an attribute.

Agreed on all fronts. I fixed the indentation when adding hide-frontmatter: true–and it worked like a charm.