diff --git a/context-v/issues/Widen-Modals-in-Obsidian-using-CSS.md b/context-v/issues/Widen-Modals-in-Obsidian-using-CSS.md deleted file mode 100644 index 6cb0f9e..0000000 --- a/context-v/issues/Widen-Modals-in-Obsidian-using-CSS.md +++ /dev/null @@ -1,687 +0,0 @@ ---- -title: "Widening (and Re-Sizing) Obsidian Plugin Modals via CSS" -date_authored: 2026-05-02 -status: Resolved -applies_to: Any Obsidian plugin Modal subclass -authored_in_context_of: perplexed → ClaudeModal -related_files: - - src/modals/ClaudeModal.ts - - src/styles/claude-modal.css - - src/styles/perplexity-modal.css # counter-example (narrow) - - src/styles/text-enhancement-modal.css # mixed example (sets max-width on contentEl, partial effect) ---- - -## TL;DR - -The block that controls a Modal's outer width is the **outer DOM element** Obsidian creates for the modal — accessed via `this.modalEl` inside `Modal.onOpen()` — **not** `this.contentEl`. If you add your CSS class to `contentEl` (which is the long-standing convention in plugin examples), your `width` / `max-width` rules apply only to the *inner* content area; the outer `.modal` element keeps Obsidian's default constraints and the modal stays narrow. - -**The one-line fix:** - -```ts -// In Modal.onOpen() -this.modalEl.addClass('my-modal'); // ← attach to the OUTER element -// not: -// this.contentEl.addClass('my-modal'); // ← inner content area only -``` - -**The matching CSS:** - -```css -.my-modal { - width: 90vw; - max-width: 640px; /* or 800px, 960px — whatever your design wants */ -} -``` - -Now `width` actually does what you'd expect. - ---- - -## The Two DOM Elements You Need to Distinguish - -Inside any class extending `Modal` (from `obsidian`), two members are exposed: - -| Field | What it is | Default classes Obsidian adds | -|--------------|------------------------------------------------------|--------------------------------| -| `this.modalEl` | The OUTER container — the popup itself | `.modal` | -| `this.contentEl` | The INNER content area — the slot you fill in | `.modal-content` | - -When Obsidian renders a modal, the DOM hierarchy looks like this (simplified): - -``` - -``` - -Obsidian's stock CSS targets `.modal` (the outer one) for the width constraints. Setting `width: 90vw` on `.modal-content` (the inner one) doesn't override the outer element's constraint — the inner one is just sized to fit *inside* whatever the outer container allows. - ---- - -## Why So Many Plugin Modals Stay Narrow - -The plugin-template convention — repeated across dozens of community plugins — is: - -```ts -onOpen() { - const { contentEl } = this; - contentEl.addClass('my-modal'); // ← the convention - contentEl.createEl('h2', { text: 'My Modal' }); - // … -} -``` - -Then: - -```css -.my-modal { - width: 90vw; /* ← applies to .modal-content; NO EFFECT on outer width */ - max-width: 800px; -} -``` - -The CSS *parses correctly*, the rules *apply*, but the outer `.modal` element is still constrained to ~600px (or whatever Obsidian's theme allows). The inner content area shrinks to fit. You get a narrow modal with extra inner whitespace and conclude "Obsidian doesn't let me size modals." That's the wrong conclusion. - -A real example from this repo shows the partial-fix attempt — `text-enhancement-modal.css`: - -```css -.text-enhancement-modal { - max-width: 800px; /* tries the right values */ - width: 90vw; - /* …but applied to contentEl, so it doesn't override the outer */ -} -``` - -Visually this modal is wider than the bare default because some theme rules let `.modal-content` push its parent open a bit, but it's still not the 800px it asks for. The `claude-modal` is, because it attaches to `modalEl`. - ---- - -## The Fix, in Full - -### Step 1 — attach the class to `modalEl` - -```ts -// src/modals/ClaudeModal.ts (excerpt) -import { App, Modal } from 'obsidian'; - -export class ClaudeModal extends Modal { - onOpen(): void { - const { contentEl, modalEl } = this; - modalEl.addClass('claude-modal'); // ← outer element gets the class - contentEl.empty(); - // …build the body here using contentEl… - } -} -``` - -### Step 2 — set width on the outer element - -```css -.claude-modal { - width: 90vw; - max-width: 640px; -} -``` - -This is enough to widen the modal. Everything below is layout polish on top. - -### Step 3 — kill the default `.modal-content` padding so your own sections control spacing - -Obsidian gives `.modal-content` an internal padding (theme-dependent, often ~20px). Once you build a custom layout with header / sections / footer, that built-in padding fights you. Zero it out and put padding on your own children: - -```css -.claude-modal .modal-content { - padding: 0; -} -``` - -Then each section you build inside `contentEl` gets its own padding: - -```css -.claude-modal__header { padding: 24px 28px 16px; } -.claude-modal__section { padding: 18px 28px 4px; } -.claude-modal__footer { padding: 16px 28px 24px; } -``` - ---- - -## Width Sizing Strategy: `vw` + `max-width` (the right way) - -```css -.claude-modal { - width: 90vw; - max-width: 640px; -} -``` - -**Why both:** - -- `width: 90vw` lets the modal grow with the viewport — feels natural on wide monitors and on a side-pane Obsidian window. On a 1440px screen, that's 1296px (clamped by `max-width`); on a 700px window, it's 630px. -- `max-width: 640px` keeps it from becoming an unreadable full-width slab on a 4K display. Pick the value based on content density: form-style modals like this one work at 600–700px; data tables or side-by-side layouts can go to 900–1100px. - -**Common width budgets that work well:** - -| Modal kind | Suggested `max-width` | -|----------------------------------------|------------------------| -| Single-column form (this modal) | 600–700px | -| Settings-dense form with inline help | 800px | -| Side-by-side / comparison | 960–1100px | -| Full content review (like a paste-in) | `min(95vw, 1200px)` | - -**Avoid** absolute pixel widths without `vw`. A bare `width: 800px` makes the modal hilariously wide on a narrow Obsidian sidepane and tiny-feeling in a maximized window. - ---- - -## Height: usually let it grow naturally - -Don't set a fixed `height` on `.claude-modal`. Obsidian's modal system handles vertical sizing fine — it grows to fit content up to a viewport-relative cap. If you have a large scrollable region inside (say, a long list), constrain *that* with `max-height`, not the whole modal: - -```css -.claude-modal__results-list { - max-height: 50vh; - overflow-y: auto; -} -``` - -If you absolutely need a bounded modal height (rare): - -```css -.claude-modal { - max-height: 85vh; -} - -.claude-modal .modal-content { - /* Let the content area scroll if it overflows */ - max-height: calc(85vh - var(--modal-chrome-height, 60px)); - overflow-y: auto; -} -``` - -But the default behavior is usually right — content-driven modals breathe better when their height isn't capped. - ---- - -## Layout Pattern: header / sections / footer - -Once you've claimed the outer width, the next problem is what to do with all that real estate. The pattern that worked here: - -```html -
-