Skip to main content

Overview

TextAreaComponent creates a <textarea> element for multi-line text input. It extends AbstractTextComponent<HTMLTextAreaElement> and is ideal for settings that require longer text input like descriptions, notes, or code snippets.

Constructor

containerEl
HTMLElement
required
The parent HTML element where the textarea will be created
const textArea = new TextAreaComponent(containerEl);

Properties

inputEl
HTMLTextAreaElement
Direct access to the underlying HTML textarea element. Use this for advanced DOM manipulation like setting rows, cols, or maxlength.
disabled
boolean
Whether the component is currently disabled

Methods

setValue

Sets the current text content of the textarea.
value
string
required
The text content to set (can include line breaks)
textArea.setValue("Line 1\nLine 2\nLine 3");
Returns: this (for method chaining)

getValue

Retrieves the current text content from the textarea.
const content = textArea.getValue();
// Returns: string (may contain \n for line breaks)
Returns: string - The current text content

setPlaceholder

Sets placeholder text that appears when the textarea is empty.
placeholder
string
required
The placeholder text to display
textArea.setPlaceholder("Enter your notes here...");
Returns: this (for method chaining)

setDisabled

Enables or disables the textarea.
disabled
boolean
required
Whether the component should be disabled
textArea.setDisabled(true);
Returns: this (for method chaining)

onChange

Registers a callback function that executes whenever the text content changes.
callback
(value: string) => any
required
Function to call when the content changes. Receives the new text value.
textArea.onChange((value) => {
  console.log(`Content changed, length: ${value.length}`);
  // Save to settings, validate, etc.
});
Returns: this (for method chaining)

onChanged

Internal method called when the value changes. Override this in subclasses for custom behavior.
textArea.onChanged();

then

Facilitates method chaining with a callback.
cb
(component: this) => any
required
Callback function that receives the component instance
textArea.then((component) => {
  component.setValue("Initial content");
});
Returns: this (for method chaining)

Usage Examples

Basic TextArea

new Setting(containerEl)
  .setName("Description")
  .setDesc("Enter a detailed description")
  .addTextArea((textArea) => {
    textArea
      .setPlaceholder("Your description here...")
      .setValue(this.plugin.settings.description)
      .onChange(async (value) => {
        this.plugin.settings.description = value;
        await this.plugin.saveSettings();
      });
  });

TextArea with Custom Size

new Setting(containerEl)
  .setName("Notes")
  .setDesc("Enter your notes")
  .addTextArea((textArea) => {
    textArea
      .setValue(this.plugin.settings.notes)
      .onChange(async (value) => {
        this.plugin.settings.notes = value;
        await this.plugin.saveSettings();
      });
    
    // Set custom dimensions
    textArea.inputEl.rows = 10;
    textArea.inputEl.cols = 50;
  });

TextArea for Code Snippets

new Setting(containerEl)
  .setName("Custom CSS")
  .setDesc("Add custom CSS rules")
  .addTextArea((textArea) => {
    textArea
      .setPlaceholder(".my-class {\n  color: red;\n}")
      .setValue(this.plugin.settings.customCss)
      .onChange(async (value) => {
        this.plugin.settings.customCss = value;
        await this.plugin.saveSettings();
        this.plugin.applyCustomCss(value);
      });
    
    // Style for code editing
    textArea.inputEl.addClass("code-editor");
    textArea.inputEl.rows = 15;
    textArea.inputEl.style.fontFamily = "monospace";
  });

TextArea with Character Counter

const counterEl = containerEl.createEl("div", { 
  cls: "character-counter" 
});

new Setting(containerEl)
  .setName("Bio")
  .setDesc("Write your bio (max 500 characters)")
  .addTextArea((textArea) => {
    const updateCounter = (value: string) => {
      const remaining = 500 - value.length;
      counterEl.setText(`${value.length}/500 characters`);
      counterEl.toggleClass("warning", remaining < 50);
    };
    
    textArea
      .setValue(this.plugin.settings.bio)
      .onChange(async (value) => {
        // Limit to 500 characters
        if (value.length > 500) {
          value = value.substring(0, 500);
          textArea.setValue(value);
        }
        
        this.plugin.settings.bio = value;
        await this.plugin.saveSettings();
        updateCounter(value);
      });
    
    // Initialize counter
    updateCounter(this.plugin.settings.bio);
    textArea.inputEl.rows = 6;
  });

TextArea with Validation

new Setting(containerEl)
  .setName("JSON Configuration")
  .setDesc("Enter valid JSON")
  .addTextArea((textArea) => {
    textArea
      .setPlaceholder('{\n  "key": "value"\n}')
      .setValue(this.plugin.settings.jsonConfig)
      .onChange(async (value) => {
        try {
          // Validate JSON
          JSON.parse(value);
          
          // Valid JSON
          this.plugin.settings.jsonConfig = value;
          await this.plugin.saveSettings();
          textArea.inputEl.removeClass("error");
        } catch (error) {
          // Invalid JSON
          textArea.inputEl.addClass("error");
          new Notice("Invalid JSON format");
        }
      });
    
    textArea.inputEl.rows = 10;
    textArea.inputEl.style.fontFamily = "monospace";
  });

Multi-line Template Editor

new Setting(containerEl)
  .setName("Note Template")
  .setDesc("Customize your note template")
  .addTextArea((textArea) => {
    const defaultTemplate = 
      "# {{title}}\n\n" +
      "Date: {{date}}\n" +
      "Tags: {{tags}}\n\n" +
      "## Notes\n";
    
    textArea
      .setPlaceholder(defaultTemplate)
      .setValue(this.plugin.settings.noteTemplate || defaultTemplate)
      .onChange(async (value) => {
        this.plugin.settings.noteTemplate = value;
        await this.plugin.saveSettings();
      });
    
    textArea.inputEl.rows = 12;
  });

Disabled TextArea

new Setting(containerEl)
  .setName("System Info")
  .setDesc("Read-only system information")
  .addTextArea((textArea) => {
    const systemInfo = [
      `OS: ${process.platform}`,
      `Version: ${this.app.vault.adapter.getName()}`,
      `Vault: ${this.app.vault.getName()}`
    ].join("\n");
    
    textArea
      .setValue(systemInfo)
      .setDisabled(true);
    
    textArea.inputEl.rows = 5;
  });

TextArea with Auto-resize

new Setting(containerEl)
  .setName("Content")
  .addTextArea((textArea) => {
    textArea
      .setValue(this.plugin.settings.content)
      .onChange(async (value) => {
        this.plugin.settings.content = value;
        await this.plugin.saveSettings();
        
        // Auto-resize based on content
        const lineCount = value.split("\n").length;
        textArea.inputEl.rows = Math.max(3, Math.min(lineCount + 1, 20));
      });
    
    // Initialize with proper size
    const initialLines = this.plugin.settings.content.split("\n").length;
    textArea.inputEl.rows = Math.max(3, Math.min(initialLines + 1, 20));
  });

TextArea for List Input

new Setting(containerEl)
  .setName("Allowed Domains")
  .setDesc("Enter one domain per line")
  .addTextArea((textArea) => {
    // Convert array to line-separated text
    const domainsText = this.plugin.settings.allowedDomains.join("\n");
    
    textArea
      .setPlaceholder("example.com\ngithub.com\nobsidian.md")
      .setValue(domainsText)
      .onChange(async (value) => {
        // Convert text back to array
        const domains = value
          .split("\n")
          .map(line => line.trim())
          .filter(line => line.length > 0);
        
        this.plugin.settings.allowedDomains = domains;
        await this.plugin.saveSettings();
      });
    
    textArea.inputEl.rows = 8;
  });

Direct DOM Access

const textArea = new TextAreaComponent(containerEl);
textArea.setValue("Initial content");

// Access the underlying textarea element
textArea.inputEl.rows = 10;
textArea.inputEl.cols = 60;
textArea.inputEl.maxLength = 1000;
textArea.inputEl.wrap = "soft";
textArea.inputEl.spellcheck = false;
textArea.inputEl.addClass("custom-textarea");

See Also

Build docs developers (and LLMs) love