CSS for Roam (2nd lesson): Power of #tags and [[pages]]

And slightly disappointing attributes

Last update: 27th December 2020

Remixed from Undraw.co .

In the first lesson, we looked at all possibilities how we can customize Roam: HTML, CSS and JavaScript. Last time, we created our very first little custom CSS: We turned the page title red. That was great! But admittedly not very useful. This time we will explore two extremely powerful elements in Roam that are probably not only most commonly customized but also their customization brings the largest benefits: They are hashtags (#tags) and [[pages]].

Before we start, a small remainder regarding the internal structure of Roam: These are the same thing:

  • [[something]] — pages
  • #something — hashtags
  • something:: — attributes

Dont you believe me? Simply try to write them in Roam, click on any of them and you will be teleported to the very same page. This unity (or rather a trinity) is one of the great powers of Roam.

Unfortunately, it is not perfect yet. At this moment, attributes are considered somewhat experimental and they cannot be customized in the same way as the other two. If we want to use pure CSS, we can style them only in a general fashion. On the other hand, [[pages]] and #tags provide great possibilities. Why? Let’s look at the code of #something using web inspector/developer tools in the same way as we learned last time.

Web inspector showing the code of #something

Have you noticed it? There is not just the basic HTML <span> tag wrapping around #something but it contains so-called HTML attributes. That might sound confusing. Haven’t we spoken about attributes just a couple of lines above? Yes but these are completely different attributes than those in Roam ending with ::.

HTML Attributes provide additional information about HTML tags. E.g. an image may have a specific width or height, or there can be a specific color for the font. Nowadays, purely visual attributes are on the decline because of the idea that HTML should convey the structure of the web page while CSS its visuals and JavaScript its interactivity. However, this does not mean the dismiss of attributes in HTML. They are still crucial: ID and classes are specific types of attributes. E.g., the class attribute of #something contains values “rm-page-ref” and “rm-page-ref--tag” (they are separated by blank spaces). If we write custom CSS and we want to change the appearance of all #tags (not just #something) we can do it by using these classes, e.g.:

.rm-page-ref--tag {
color: red;

The result is similar to our last exercise: instead of the title turning red, we made #something turn red:

Remember: This applies to all #tags:

Luckily, since HTML 5, the programmers can also create custom attributes. These are called “data-*” attributes. As their name suggests, they contain additional data information and they furthermore support the idea that HTML should describe the structure, not visuals. In Roam, you can find these “data-*” attributes in various different places. E.g., have you already used {{[[POMO]]}} — the pomodoro timer in Roam? This is its HTML representation:

As you can see, there are three “data-*” attributes:

In the case of #something, there is just one custom attribute but one of the great power: data-tag. It contains the name of the tag! Now you might ask: Why? How could this help us? As you may remember from the previous lesson, CSS can select tags based on multiple different conditions, like their type, ID, class, attribute and position. However, it cannot select tags based on their content. By putting the name of the tag into the attribute it allows us to select it easily by CSS.

The syntax for selecting a tag based on a specific value of its attribute is the following:


This means that we can now select only the tag with the specific name of “something”:

[data-tag="something"] {

Now, only #something is turning red:

Turning only #something red.

Probably the most common properties to be changed by Roam users are the following two:

The colors can be inserted using color names (like “red”, “blue”, “yellow”) or color values (like #FF0000, #0000FF, #FFFF00).

Also, you can add borders using some of many properties:

Now we can apply them all to #something:

[data-tag="something"] {
border-color: orange;
border-style: solid;
border-width: 1px;
border-radius: 5px;

Not bad but as you can see, it is a little bit cramped. To solve this issue, we can add padding properties:

As we have said before, [[pages]] and #tags are the same thing. So why does our script not affect [[something]]? This can be, again, very easily discovered by using the web inspector/developer tools:

Code of [[something]]

The code is more complicated here because of the nested <span> tags with various classes and attributes. However, important for us is that the first, parent <span> has two “data-*” attributes:

  • data-link-title — same as data-tag
  • data-link-uid — ID of the linked page

This means we can adapt our previous code to select both [[something]] and #something. We can do it by using , as a separator between various selectors.

[data-link-title="something"] {
border-color: orange;
border-style: solid;
border-width: 1px;
border-radius: 5px;
padding-left: 3px;
padding-right: 3px;
Code of [[something]]

Almost there. As you can see, the color of the link is still blue and not orange. The reason is that the default styling has priority over our own custom one. There are more ways how to deal with it. Probably the easiest would be to select separately the middle nested <span> and change its color.

Better custom CSS for [[something]]

This is good! Almost … again. As you may notice, now we have a similar problem as before: all page references are orange! Don’t worry, there is also a solution for this: the so-called “complex” selectors. We will learn more about them next time. Now just remember that if you want to select a nested element, you write simply the selector of its ancestor (in our case [data-link-title="something"]), a blank space, and the selector of the nested element:

That is all. Now everything should work as intended.

On this occasion, we have learned how to style specific [[pages]] and #tags based on their “data-*” attributes. This is only possible because of the clever design of Roam. The use of these attributes with the purpose to facilitate custom styling is not common among web developers. We can only hope that the developers of Roam will soon also add “data-*” attributes to Roam :: attributes, as well as to other elements.

Next time, we will continue with more examples of the amazing power of [[pages]] and #tags .

If you like my work, follow me on Twitter, check the public Roam database Roam-tricks, my personal public collection of my hacks, and yes, you can support me on Patreon or through PayPal . I would really appreciate it and you would help to make future articles happen. And remember: If it looks like a duck, if it writes like a duck, it’s probably me. [[QUACK]]!

PS: Thanks Ranjit Parekh for cathing a small mistake in this article :). If you find any issue in this article or have any other feedback here, please, don’t hesitate to contact me. The best way is on Twitter via a direct message.

Just a humble Roaman duck.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store