From 2233e8fb916288981007c89b6a16edf85d1c3746 Mon Sep 17 00:00:00 2001 From: Frank Stellmacher <171614930+Psychotoxical@users.noreply.github.com> Date: Sat, 16 May 2026 13:22:59 +0200 Subject: [PATCH] fix(album): contain Artist Biography modal scroll within frame (#734) * fix(album): contain Artist Biography modal scroll within frame The modal was rendered inside the album page tree, where an ancestor broke `position: fixed` so the overlay scrolled with the page instead of pinning to the viewport. Long bios also pushed the modal past the viewport entirely. - Render `BioModal` via `createPortal(document.body)` so no ancestor's transform/filter/backdrop-filter can break fixed positioning. - New `.modal-content.bio-modal` variant: flex column, `overflow: hidden`. Title + close button stay pinned, only `.bio-modal-body` scrolls. The existing `max-height: 80vh` on `.modal-content` now reliably caps the modal to the visible viewport. Reported by zunoz on Discord. * docs(changelog): note Artist Biography modal scroll fix (#734) --- CHANGELOG.md | 7 +++++++ src/components/AlbumHeader.tsx | 12 ++++++++---- src/styles/components/modal.css | 15 +++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c97252ff..953cf9f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -565,6 +565,13 @@ Foundational work: faster reviews, narrower diffs, and a safety net under the pa * The Album header showed an **Artist Bio** button on every album, but when the album-artist label is **"Various Artists"**, **"Various"**, **"VA"** or a language equivalent there is no single artist to fetch a bio for and the button opened an empty modal. Both the mobile icon and the desktop button are now hidden when the album-artist label matches that compilation heuristic. +### Album header — Artist Biography modal stays in viewport and scrolls internally + +**By [@Psychotoxical](https://github.com/Psychotoxical), thanks to zunoz for the report on the Psysonic Discord, PR [#734](https://github.com/Psychotoxical/psysonic/pull/734)** + +* The **Artist Biography** modal lived under the album page tree, where an ancestor broke **`position: fixed`** on the overlay — opening a long bio scrolled the whole page instead of staying pinned to the viewport, and the modal itself stretched past the visible area. It now mounts via **`createPortal(..., document.body)`** (same approach as **`RadioEditModal`** / **`CoverLightbox`**), so the overlay always pins to the viewport. +* A new **`.modal-content.bio-modal`** variant turns the modal into a flex column with **`overflow: hidden`** and an inner **`.bio-modal-body`** that handles the scrolling. The existing **`max-height: 80vh`** cap is now honored, and the title + close button stay pinned while the bio scrolls. + ## [1.45.0] - 2026-05-04 ## Added diff --git a/src/components/AlbumHeader.tsx b/src/components/AlbumHeader.tsx index ef996005..aeecd681 100644 --- a/src/components/AlbumHeader.tsx +++ b/src/components/AlbumHeader.tsx @@ -1,6 +1,7 @@ import { buildCoverArtUrl } from '../api/subsonicStreamUrl'; import type { EntityRatingSupportLevel, SubsonicOpenArtistRef, SubsonicSong } from '../api/subsonicTypes'; import React, { useMemo, useState } from 'react'; +import { createPortal } from 'react-dom'; import { useNavigate } from 'react-router-dom'; import { Play, Heart, ExternalLink, X, ChevronLeft, Download, ListPlus, HardDriveDownload, Share2, Highlighter, Loader2, Shuffle } from 'lucide-react'; import CachedImage from './CachedImage'; @@ -35,14 +36,17 @@ function isVariousArtistsLabel(name: string | undefined | null): boolean { function BioModal({ bio, onClose }: { bio: string; onClose: () => void }) { const { t } = useTranslation(); - return ( + return createPortal(