Modals display information and accept input from the user. To create a modal, create a class that extends [[Reference/TypeScript API/Modal|Modal]]: ```ts import { App, Modal } from "obsidian"; export class ExampleModal extends Modal { constructor(app: App) { super(app); } onOpen() { let { contentEl } = this; contentEl.setText("Look at me, I'm a modal! 👀"); } onClose() { let { contentEl } = this; contentEl.empty(); } } ``` - [[Reference/TypeScript API/View/onOpen|onOpen()]] is called when the modal is opened and is responsible for building the content of your modal. For more information, refer to [HTML elements](HTML%20elements.md). - [[Reference/TypeScript API/Modal/onClose|onClose()]] is called when the modal is closed and is responsible for cleaning up any resources used by the modal. To open a modal, create a new instance of `ExampleModal` and call [[Reference/TypeScript API/Modal/open|open()]] on it: ```ts import { Plugin } from "obsidian"; import { ExampleModal } from "./modal"; export default class ExamplePlugin extends Plugin { async onload() { this.addCommand({ id: "display-modal", name: "Display modal", callback: () => { new ExampleModal(this.app).open(); }, }); } } ``` ## Accept user input The modal in the previous example only displayed some text. Let's look at a little more complex example that handles input from the user. ![[modal-input.png]] ```ts import { App, Modal, Setting } from "obsidian"; export class ExampleModal extends Modal { result: string; onSubmit: (result: string) => void; constructor(app: App, onSubmit: (result: string) => void) { super(app); this.onSubmit = onSubmit; } onOpen() { const { contentEl } = this; contentEl.createEl("h1", { text: "What's your name?" }); new Setting(contentEl) .setName("Name") .addText((text) => text.onChange((value) => { this.result = value })); new Setting(contentEl) .addButton((btn) => btn .setButtonText("Submit") .setCta() .onClick(() => { this.close(); this.onSubmit(this.result); })); } onClose() { let { contentEl } = this; contentEl.empty(); } } ``` The result is stored in `this.result` and returned in the `onSubmit` callback when the user clicks **Submit**: ```ts new ExampleModal(this.app, (result) => { new Notice(`Hello, ${result}!`); }).open(); ``` ## Select from list of suggestions [[SuggestModal|SuggestModal]] is a special modal that lets you display a list of suggestions to the user. ![[suggest-modal.gif]] ```ts import { App, Notice, SuggestModal } from "obsidian"; interface Book { title: string; author: string; } const ALL_BOOKS = [ { title: "How to Take Smart Notes", author: "Sönke Ahrens", }, { title: "Thinking, Fast and Slow", author: "Daniel Kahneman", }, { title: "Deep Work", author: "Cal Newport", }, ]; export class ExampleModal extends SuggestModal<Book> { // Returns all available suggestions. getSuggestions(query: string): Book[] { return ALL_BOOKS.filter((book) => book.title.toLowerCase().includes(query.toLowerCase()) ); } // Renders each suggestion item. renderSuggestion(book: Book, el: HTMLElement) { el.createEl("div", { text: book.title }); el.createEl("small", { text: book.author }); } // Perform action on the selected suggestion. onChooseSuggestion(book: Book, evt: MouseEvent | KeyboardEvent) { new Notice(`Selected ${book.title}`); } } ``` In addition to `SuggestModal`, the Obsidian API provides an even more specialized type of modal for suggestions: the [[FuzzySuggestModal|FuzzySuggestModal]]. While it doesn't give you the same control of how each item is rendered, you get [fuzzy string search](https://en.wikipedia.org/wiki/Approximate_string_matching) out-of-the-box. ![[fuzzy-suggestion-modal.png]] ```ts export class ExampleModal extends FuzzySuggestModal<Book> { getItems(): Book[] { return ALL_BOOKS; } getItemText(book: Book): string { return book.title; } onChooseItem(book: Book, evt: MouseEvent | KeyboardEvent) { new Notice(`Selected ${book.title}`); } } ```