Skip to content

Conversation

@abdultalha0862
Copy link

@abdultalha0862 abdultalha0862 commented Nov 4, 2025

Description

Brief summary of changes:

Fixed email preview modal to display a visible scrollbar and support full keyboard navigation. Users can now scroll email previews using drag-and-drop on the scrollbar, keyboard navigation (arrows/Page Up/Down), or the mouse wheel.

Related issue(s):

Fixes #25304

Type of change:

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality not to work as expected)
  • Documentation update
  • Code refactoring
  • Performance improvement
  • UI/UX improvement

Testing

How has this been tested?

  • Manual testing
  • Unit tests
  • Integration tests
  • End-to-end tests

Test environment:

  • Ghost version: 5.x (development main branch)
  • Node.js version: v22.19.0
  • Database (MySQL/SQLite): SQLite
  • Browser (if applicable): Chrome/Chromium 142.0

Manual Testing Performed

Keyboard Navigation:

  • ✅ Tab key moves focus into email preview iframe
  • ✅ Arrow Up/Down keys scroll the preview content
  • ✅ Page Up/Down keys scroll by viewport height
  • ✅ Space/Shift+Space scroll down/up
  • ✅ Focus indicator (blue outline) visible on iframe

Mouse/Trackpad:

  • ✅ Visible scrollbar appears when content overflows
  • ✅ Scrollbar can be dragged with the mouse
  • ✅ Mouse wheel scrolling still works
  • ✅ Clicking inside the preview maintains focus

Automated Test Results

cd ghost/admin
CHROME_BIN=$(command -v chromium) ember test --launch "Chromium" -f 'Post email preview'

# tests 6
# pass  6
# skip  0
# fail  0

Added acceptance test:
" allows keyboard users to focus and scroll the email preview" that validates:

  • Iframe has tabindex="0"
  • Focus event triggers body focus
  • Body receives tabindex="-1" for keyboard events

Screenshots

Before:

  • No visible scrollbar in email preview
  • Keyboard navigation (arrows/Page Up/Down) is non-functional
  • Users had to rely solely on the mouse wheel or clicking and dragging content

After:

  • Visible scrollbar when content overflows
  • Full keyboard navigation support via Tab → arrow keys/Page Up/Down
  • All existing mouse interactions preserved
Issue_After_Fix_25304.mp4

Checklist

Code Quality

  • My code follows Ghost's coding standards
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings or errors
  • I have added JSDoc comments for new functions/methods

Testing

  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have tested this change across different browsers (if UI-related)
  • I have tested this change with different Ghost configurations

Documentation

  • I have made corresponding changes to the documentation
  • I have updated relevant code comments
  • Any breaking changes are documented

Ghost-Specific

  • I have tested this with both MySQL and SQLite databases (tested with SQLite only)
  • Changes work correctly in both development and production modes
  • I have considered the impact on existing Ghost installations
  • Admin UI changes are responsive and accessible
  • Theme changes are backwards compatible (if applicable) (N/A - admin-only change)

Additional Notes

Implementation Details

1. CSS Changes (email.js):

``JavaScriptt
// Before
const INJECTED_CSS = html::-webkit-scrollbar { display: none; width: 0; background: transparent } html { scrollbar-width: none; };

// After
const INJECTED_CSS = html, body { overflow-y: auto; };


**2. Accessibility Improvements (`email.hbs`):**

* Added `tabindex="0"` to iframe for keyboard focus
* Added `{{on "focusin" this.focusPreviewFrame}}` event handler

**3. Focus Management (`email.js`):**

```JavaScript
@action
focusPreviewFrame(event) {
    // Programmatically focuses iframe body
    // Sets tabindex="-1" on body for keyboard events
    // Includes cross-origin fallback to window.focus()
}

Note

Enable visible scrolling and keyboard navigation in the email preview by injecting overflow CSS and focusing the iframe body; adds acceptance test.

  • Admin UI
    • Email preview iframe (editor/modals/preview/email.hbs, email.js):
      • Add tabindex="0" and focusin handler to set focus on iframe body (adds tabindex="-1" fallback to contentWindow.focus()).
      • Update injected CSS to html, body { overflow-y: auto; } for visible scrolling inside the iframe.
  • Tests
    • Acceptance (post-email-preview-test.js):
      • Add test ensuring iframe is keyboard-focusable and body receives focus with tabindex="-1".

Written by Cursor Bugbot for commit efa651b. This will update automatically on new commits. Configure here.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 4, 2025

Walkthrough

Replaces CSS that hid scrollbars with overflow-y: auto on the iframe html/body, adds tabindex="0" to the preview iframe, and introduces a focusPreviewFrame(event) action that safely focuses the iframe content (managing tabindex and handling errors). Adds an acceptance test that verifies the iframe has tabindex="0", that triggering focusin focuses the iframe document body, and that the body receives a tabindex="-1" as part of the focus workflow.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Check email.js focus logic: try/catch, use of preventScroll, tabindex manipulation, and cross-origin/frame availability handling.
  • Verify the injected CSS change (overflow-y: auto) does not introduce layout regressions.
  • Review email.hbs iframe attribute addition for accessibility and semantic correctness.
  • Validate the new acceptance test (post-email-preview-test.js) for stability and timing (use of waitFor/waitUntil and triggerEvent).

Pre-merge checks and finishing touches

✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the primary changes: fixing email preview scrollbar visibility and keyboard accessibility, which aligns with the main objectives of the PR.
Description check ✅ Passed The description provides detailed context about the bug fix, including technical changes, testing approach, and manual verification steps that directly relate to the changeset modifications.
Linked Issues check ✅ Passed The PR successfully addresses issue #25304 by implementing visible scrollbar support (CSS injection change) and keyboard navigation (tabindex, focusin handler, and focusPreviewFrame action), meeting the stated objectives.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the email preview scrollbar and keyboard accessibility; no extraneous modifications or unrelated code changes are present in the changeset.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1213fb6 and efa651b.

📒 Files selected for processing (3)
  • ghost/admin/app/components/editor/modals/preview/email.hbs (1 hunks)
  • ghost/admin/app/components/editor/modals/preview/email.js (3 hunks)
  • ghost/admin/tests/acceptance/editor/post-email-preview-test.js (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • ghost/admin/tests/acceptance/editor/post-email-preview-test.js
  • ghost/admin/app/components/editor/modals/preview/email.js
  • ghost/admin/app/components/editor/modals/preview/email.hbs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
ghost/admin/tests/acceptance/editor/post-email-preview-test.js (1)

119-137: Consider clarifying test scope in the title.

The test thoroughly validates the focus behavior prerequisites for keyboard scrolling (iframe focusability, body focus, tabindex attributes). However, the test title mentions "scroll" but doesn't actually test scrolling behavior (e.g., simulating Arrow keys and verifying scroll position changes).

Consider either:

  1. Renaming to something like "allows keyboard users to focus the email preview for keyboard navigation"
  2. Adding assertions that simulate keyboard events and verify scrolling occurs

That said, testing actual scroll behavior may be complex and potentially fragile. The current test validates the critical prerequisites for keyboard scrolling to work, which may be sufficient.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0056dab and 1213fb6.

📒 Files selected for processing (3)
  • ghost/admin/app/components/editor/modals/preview/email.hbs (1 hunks)
  • ghost/admin/app/components/editor/modals/preview/email.js (3 hunks)
  • ghost/admin/tests/acceptance/editor/post-email-preview-test.js (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-11T14:18:31.752Z
Learnt from: niranjan-uma-shankar
Repo: TryGhost/Ghost PR: 24626
File: apps/portal/src/components/pages/AccountHomePage/components/AccountFooter.js:15-15
Timestamp: 2025-08-11T14:18:31.752Z
Learning: In Ghost, Portal components render within iframes while admin components (like gh-member-details.hbs, dashboard/charts/recents.hbs, and posts/post-activity-feed.hbs) do not render in iframes. Therefore, iframe-related navigation issues only affect Portal components.

Applied to files:

  • ghost/admin/app/components/editor/modals/preview/email.hbs
📚 Learning: 2025-10-15T07:53:49.814Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-10-15T07:53:49.814Z
Learning: Use Vitest + Testing Library + jsdom for tests; prioritize focused unit tests for hooks/utils/logic-heavy parts

Applied to files:

  • ghost/admin/tests/acceptance/editor/post-email-preview-test.js
🧬 Code graph analysis (1)
ghost/admin/app/components/editor/modals/preview/email.js (1)
ghost/admin/tests/acceptance/editor/post-email-preview-test.js (1)
  • iframe (123-123)
🔇 Additional comments (6)
ghost/admin/app/components/editor/modals/preview/email.hbs (2)

94-94: LGTM! Good accessibility practice.

Adding tabindex="0" correctly makes the iframe keyboard-focusable, allowing users to reach the email preview content via Tab navigation.


98-98: LGTM! Correct event choice for focus handling.

Using focusin (which bubbles) is the right choice for iframe focus detection. This works in tandem with tabindex="0" to enable keyboard navigation into the preview.

ghost/admin/app/components/editor/modals/preview/email.js (3)

10-14: LGTM! Correct CSS for scrollbar visibility.

Using overflow-y: auto appropriately shows the vertical scrollbar when content overflows and hides it when content fits, directly addressing the issue. This is preferable to overflow-y: scroll, which would always show a scrollbar track.


79-106: LGTM! Robust focus management with proper fallbacks.

The implementation correctly:

  • Sets tabindex="-1" on the iframe body for programmatic focus (not tab-reachable)
  • Uses preventScroll: true to avoid scrolling the outer page when focusing the iframe
  • Provides fallbacks for older browsers that don't support preventScroll
  • Handles edge cases where body might not be available
  • Gracefully degrades to window focus on errors

The nested try-catch structure appropriately handles different failure scenarios.


183-183: LGTM! Comment accurately reflects the CSS behavior.

The updated comment better describes the purpose of the injected CSS without prescribing specific implementation details.

ghost/admin/tests/acceptance/editor/post-email-preview-test.js (1)

2-2: LGTM! Necessary test helper imports.

The added imports (triggerEvent, waitFor, waitUntil) are all used in the new keyboard navigation test and are standard Ember testing helpers.

fixes TryGhost#25304

Users with two-button mice or keyboard-only workflows could not scroll email previews effectively. The iframe lacked a visible scrollbar and was not keyboard-accessible, creating barriers for accessibility-focused users and those using non-wheel input devices. This fix addresses immediate user pain reported in Windows 11 environments where visible scrollbars are expected UI patterns.
@abdultalha0862 abdultalha0862 force-pushed the fix/25304-email-preview-scrollbar branch from 1213fb6 to efa651b Compare November 6, 2025 03:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant