Cyrillic and Non-Latin Tags

approved

by Kirill Chokparov

Adds custom CSS classes to tags containing any non-Latin letters (cyrillic, hieroglyphs, diacritics, etc.) in Editing view. Enables styling non-Latin tags via CSS snippets and third-party plugins. - This plugin has not been manually reviewed by Obsidian staff.

76 downloadsUpdated 1mo agoMIT

English | Русский

Cyrillic and Non-Latin Tags (Obsidian Plugin)

The plugin adds custom CSS classes to tags containing any non-Latin letters (cyrillic, hieroglyphs, diacritics, etc.) in Editing view.

This allows you to customize the appearance of non-Latin tags via CSS or configure their styling using third-party plugins (such as Colored Tags Wrangler).

How It Works for the User

Simply install and enable the plugin in your Obsidian settings. It requires zero configuration and is controlled by a single toggle switch.

The plugin analyzes the tag content and processes only those that contain at least one non-Latin letter.

Latin tags (e.g., #task) remain untouched and retain standard Obsidian classes.

Non-Latin tags receive two additional classes:

  • Generic class: cm-tag-non-latin — for styling all non-Latin tags.
  • Personal dynamic class: cm-tag-[tag_name] — for fine-tuning specific tags.

Example 1. The #завершено tag will receive the generic class cm-tag-non-latin and the personal class cm-tag-завершено.

Example 2. The #초봄날 tag will receive the generic cm-tag-non-latin class and the personal cm-tag-초봄날 class.

CSS Styling Examples

You can use these classes in your CSS snippet inside the .obsidian/snippets folder to visually highlight your tags.

Styling All Non-Latin Tags

.cm-tag-non-latin { 
    background-color: green; 
    color: whitesmoke; 
}  

Styling a Particular Non-Latin Tag

The #завершено tag:

.cm-tag-завершено { 
    background-color: royalblue; 
    color: #ffffff; 
    font-weight: bold; 
} 

The #초봄날 tag:

.cm-tag-초봄날 {
    background-color: #E2F0D9;
    color: #386641;
}

Working with Nested Tags (Forward Slash)

Following the Obsidian style for Latin tags, the plugin removes slashes in the class name for nested non-Latin tags, such as #книга/глава1/часть2.

In the DOM structure, the class name looks like this: <span class="cm-tag-книгаглава1часть2">.

Styling in the CSS file:

.cm-tag-книгаглава1часть2 {  
    color: grey;  
    background-color: mistyrose;
}

This approach also ensures compatibility with third-party plugins for styling nested non-Latin tags.

Emojis and digits

Emojis and digits (e.g., #test😊, #task123) do not turn a tag into a non-Latin one if all other letters inside it are Latin.

Implementation Details for Developers

Each tag in Obsidian is composed of multiple <span> elements. When the plugin detects a non-Latin tag, it iterates through all its constituent HTML elements and injects custom classes into their class attribute.

Elements of Latin tags remain untouched.

Nested <span> Elements

When a class is added to a <span> element, an additional nested <span> element is automatically generated within the DOM structure, which then holds the actual tag content.

The resulting structure looks like this:

<span class="..."> <!-- original parent element -->
	<span class="...">tag_name</span> <!-- nested element -->
</span>

The plugin only adds new classes to the nested <span> elements. Parent elements retain their original Obsidian classes.

Compatibility with Third-Party Plugins

To ensure third-party plugins can recognize and style tags processed by this plugin, the nested <span> elements must contain the standard Obsidian cm-hashtag class. Therefore, the plugin also injects the class into these elements.

Nested Elements and Style Preservation

When a nested structure of elements containing the cm-hashtag class appears, the default styling breaks: extra paddings/margins appear, and the tag's font size decreases.

This happens due to the following class layering:

<span class="cm-hashtag ..."> <!-- parent element -->
	<span class="cm-hashtag ...">tag_name</span> <!-- nested element -->
</span>

To preserve the original style, the plugin integrates a custom theme extension that neutralizes the parent <span> element's impact on non-Latin tags:

const tagThemeExtension = EditorView.theme({
    ".cm-hashtag:has(.cm-tag-non-latin)": {
        display: "contents !important",
        fontSize: "inherit !important",
        lineHeight: "inherit !important",
        fontFamily: "inherit !important",
        fontWeight: "inherit !important"
    }
});

DOM Structure

A tag in Obsidian is composed of two or more <span> elements. By traversing the syntax tree and analyzing the nodes, the plugin injects the following additional classes into the elements of non-Latin tags.

Classes for All <span> Elements

  • cm-hashtag — base Obsidian system class.
  • cm-tag-non-latin — global class for all non-Latin tags.
  • cm-tag-[tag_name] — personal dynamic class. The tag name is generated "as is", preserving all characters except for forward slashes (/).

Boundary Classes for Tag Limits

  1. The first element (the # symbol) additionally receives the cm-hashtag-begin class.
  2. The last element (the end of the tag) additionally receives the cm-hashtag-end class.

Example: DOM Structure for the tag

Let's consider the #тег_тест tag.

Obsidian splits this tag with an underscore into three separate <span> elements. The plugin locates them in the syntax tree and appends the custom classes:

<!-- 1. First element (the '#' symbol) -->
<span class="cm-hashtag cm-hashtag-begin cm-tag-non-latin cm-tag-тег_тест">#</span> 

<!-- 2. Second element -->
<span class="cm-hashtag cm-tag-non-latin cm-tag-тег_тест">тег_</span> 

<!-- 3. Last element -->
<span class="cm-hashtag cm-hashtag-end cm-tag-non-latin cm-tag-тег_тест">тест</span> 

Testing

The source code is covered by unit tests using Vitest. The tests verify various linguistic combinations, edge-case ASCII characters, nested tags and emojis.

License

This project is distributed under the free MIT License.

For plugin developers

Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.