Register a new file type in Obsidian

Here’s a quick reference for creating a new filetype in Obsidian plugin development. It doesn’t go into the absolute basics, so if you’re new to plugin development, refer to the Obsidian developer docs.

For reference, here’s the primary code structure in the main.js file. So we can understand where the new code will live.

Main.js:

import { Plugin } from "obsidian";

/////////

export default class ExamplePlugin extends Plugin {
  async onload() {
    // The code we define will go here.
  }
  async onunload() {}
}

You can find the above explained in more detail in Obsidian’s Anatomy of a Plugin.

A wrapper for a markdown file

If all you want to do is have Obsidian treat your file extension just like it treats its standard Markdown files, you only need to add one line in the place commented above.

this.registerExtensions(['tdo'], 'markdown');

In the above line, the this keyword refers to the instance of your plugin class. The tdo is the file extension we want Obsidian to recognise (ie. MyFile.tdo), and markdown is the unique name for the Markdown view type in Obsidian.

This means that now, *.tdo files will appear in the Obsidian file browser, and when clicked on, the standard Obsidian note editor will open and show any text as in the file as editable markdown.

A different file format

In the above example we were just emulating Markdown behaviour in a file with a different extension, but if we want to define a way to display a file that isn’t in Markdown, we need to do a little more.

As usual, we still register the extension we want Obsidian to recognise, but this time, we define our own view type.

this.registerExtensions(['svg'], 'svg-view');

That means that files with the extension SVG will appear in Obsidian now, and when the user clicks on one it will open an svg-view.

This means we also have to tell Obsidian how an svg-view works.

this.registerView(
    'svg-view',
    (leaf) => new SvgView(leaf, plugin)
);

In the above code, we register svg-view as a view type, which when clicked, will run the view creator function we’ve defined in the second parameter.

The view creator function has a leaf parameter, which will correspond to the panel on screen that Obsidian is trying to open the file in. Our function tells it to create a new SvgView in that panel.

Which means the next thing we need to do is define the SvgView function.

In another file:

export class SvgView extends TextFileView {

    constructor(leaf: WorkspaceLeaf, plugin: Plugin) {
        super(leaf);
    }

    getViewType(): string {
        return 'svg-view';
    }

    getDisplayText = () => {
        return 'Svg file';
    }

    // This provides the data from the file for placing into the view
    // (Called when file is opening)
    setViewData = (fileContents: string, clear: boolean) => {
        // Get the main area of the view
        const viewDomContent = this.containerEl.children[1];
        // Do stuff add the data to the content area of the view to displau it how you like.
    }

    // This allows you to return the data you want Obsidian to save
    // (Called when file is closing)
    getViewData = (): string => {
        return //theData
    }

}

The above code doesn’t do anything. It’s just the basic structure that you would use to define how the view works. Read the comments and view the TextFileView docs. for more detail.

A note on organisation

While I’ve implied above that the registration of the view and the registration of the filetype goes straight into main.js, personally, I prefer to keep the view code all together in another file and call its instantiation from a function.

But either setup will work.

main.js:

import { Plugin } from "obsidian";

/////////

export default class ExamplePlugin extends Plugin {

  async onload() {
    registerSvgViewAndFiletype(this);
  }

  async onunload() {}

}

anotherFile.tsx:

export function registerSvgViewAndFiletype(plugin: Plugin) {
    plugin.registerView(
        'svg-view',
        (leaf) => new SvgView(leaf, plugin)
    );
    plugin.registerExtensions(['svg'], 'svg-view');
}

class SvgView extends TextFileView {
    ...
}

That’s it!

Thanks…

I also dissect and speculate on design and development.
Digging into subtle details and implications, and exploring broad perspectives and potential paradigm shifts.
Check out my conceptual articles on Substack or find my latest below.


You can also find me on Threads, Bluesky, Mastodon, or X for more diverse posts about ongoing projects.

My latest articles

Focal point blocking for XR media

Planning out a linear VR experience requires thinking about where the viewers attention might be. Thinking about the focal points…

Designing immersive experiences

In traditional cinema, TV, or even the more modern phone screen, there’s limited screen real-estate. But removing that limitation creates a design problem…

The future is not prompt engineered

Let’s not pretend the importance of prompt engineering is ubiquitous. The most prevalent power of generative AI is in the way it adapts to us, not the other way around…

Author:

Date:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.