Skip to main content
The ItemView class extends View and provides a content area and action buttons. This is the base class for most custom views.

Properties

contentEl
HTMLElement
The main content element for this view. Use this to add your view’s content.

Inherited Properties

ItemView inherits all properties from View:
  • app: App
  • icon: IconName
  • navigation: boolean
  • leaf: WorkspaceLeaf
  • containerEl: HTMLElement
  • scope: Scope | null

Constructor

constructor(leaf: WorkspaceLeaf)
leaf
WorkspaceLeaf
required
The workspace leaf this view will be attached to

Methods

addAction()

Adds an action button to the view’s header.
addAction(
  icon: IconName,
  title: string,
  callback: (evt: MouseEvent) => any
): HTMLElement
icon
IconName
required
The icon for the action button. See Icons documentation for available icons.
title
string
required
The tooltip text for the action button
callback
(evt: MouseEvent) => any
required
Function to call when the action is clicked
return
HTMLElement
The created action button element
Since: 1.1.0

Example

class MyCustomView extends ItemView {
  async onOpen() {
    const container = this.contentEl;
    container.empty();
    container.createEl('h4', { text: 'My View' });

    // Add action buttons
    this.addAction('refresh-cw', 'Refresh', () => {
      this.refresh();
    });

    this.addAction('download', 'Export', () => {
      this.exportData();
    });
  }

  refresh() {
    console.log('Refreshing view...');
  }

  exportData() {
    console.log('Exporting data...');
  }
}

Inherited Methods

ItemView inherits all methods from View:
  • onOpen(): Called when view is opened
  • onClose(): Called when view is closed
  • getViewType(): Returns the view type identifier
  • getDisplayText(): Returns the display text
  • getState(): Gets the view state
  • setState(): Sets the view state
  • getEphemeralState(): Gets ephemeral state
  • setEphemeralState(): Sets ephemeral state
  • getIcon(): Gets the view icon
  • onResize(): Called when view is resized
  • onPaneMenu(): Populates the pane menu

Creating a Custom ItemView

Here’s a complete example of creating a custom view with ItemView:
import { ItemView, WorkspaceLeaf } from 'obsidian';

const VIEW_TYPE_EXAMPLE = 'example-view';

class ExampleView extends ItemView {
  constructor(leaf: WorkspaceLeaf) {
    super(leaf);
  }

  getViewType() {
    return VIEW_TYPE_EXAMPLE;
  }

  getDisplayText() {
    return 'Example view';
  }

  async onOpen() {
    const container = this.contentEl;
    container.empty();
    
    container.createEl('h4', { text: 'Example View' });
    
    const listEl = container.createEl('ul');
    listEl.createEl('li', { text: 'Item 1' });
    listEl.createEl('li', { text: 'Item 2' });
    listEl.createEl('li', { text: 'Item 3' });

    // Add action buttons
    this.addAction('plus', 'Add item', () => {
      listEl.createEl('li', { text: `Item ${listEl.children.length + 1}` });
    });

    this.addAction('trash', 'Clear items', () => {
      listEl.empty();
    });
  }

  async onClose() {
    // Cleanup
  }
}

Registering and Opening the View

import { Plugin } from 'obsidian';

export default class ExamplePlugin extends Plugin {
  async onload() {
    // Register the view
    this.registerView(
      VIEW_TYPE_EXAMPLE,
      (leaf) => new ExampleView(leaf)
    );

    // Add ribbon icon to open the view
    this.addRibbonIcon('dice', 'Open example view', () => {
      this.activateView();
    });

    // Add command to open the view
    this.addCommand({
      id: 'open-example-view',
      name: 'Open example view',
      callback: () => {
        this.activateView();
      }
    });
  }

  async activateView() {
    const { workspace } = this.app;

    let leaf = workspace.getLeavesOfType(VIEW_TYPE_EXAMPLE)[0];

    if (!leaf) {
      leaf = workspace.getRightLeaf(false);
      await leaf.setViewState({ type: VIEW_TYPE_EXAMPLE, active: true });
    }

    workspace.revealLeaf(leaf);
  }

  async onunload() {
    // Detach all leaves of this type
    this.app.workspace.detachLeavesOfType(VIEW_TYPE_EXAMPLE);
  }
}

Best Practices

1. Always clean up in onClose()

class MyView extends ItemView {
  private interval: number;

  async onOpen() {
    this.interval = window.setInterval(() => {
      // Update view
    }, 1000);
  }

  async onClose() {
    if (this.interval) {
      window.clearInterval(this.interval);
    }
  }
}

2. Use contentEl for your content

The contentEl is the designated content area. Don’t modify containerEl directly.
async onOpen() {
  const container = this.contentEl;
  container.empty();
  // Add your content to container
}

3. Handle resize events

onResize() {
  // Recalculate layout if needed
  this.updateLayout();
}

4. Save and restore state

getState() {
  return {
    selectedTab: this.selectedTab,
    scrollPosition: this.scrollPosition
  };
}

async setState(state: any, result: ViewStateResult) {
  this.selectedTab = state.selectedTab || 0;
  this.scrollPosition = state.scrollPosition || 0;
  await super.setState(state, result);
}

Common Use Cases

Creating a sidebar view

this.addCommand({
  id: 'open-sidebar-view',
  name: 'Open sidebar view',
  callback: async () => {
    const leaf = this.app.workspace.getRightLeaf(false);
    await leaf.setViewState({
      type: VIEW_TYPE,
      active: true
    });
    this.app.workspace.revealLeaf(leaf);
  }
});

Creating a main area view

this.addCommand({
  id: 'open-main-view',
  name: 'Open main view',
  callback: async () => {
    const leaf = this.app.workspace.getLeaf('tab');
    await leaf.setViewState({
      type: VIEW_TYPE,
      active: true
    });
  }
});

See Also

Build docs developers (and LLMs) love