fix(tv): keep focus on search field instead of jumping to results grid

On the Apple TV search page, the native tvOS search field owns focus while
typing. Both result renderers set hasTVPreferredFocus on their first item,
which re-requests focus on every re-render. Since results re-render on each
keystroke, the first poster kept yanking focus out of the search field into
the grid.

Stop search results from requesting preferred focus in both Library and
Discover modes; the user navigates down to the grid manually (standard tvOS
.searchable behavior).
This commit is contained in:
Fredrik Burmester
2026-06-01 12:38:26 +02:00
parent 32c99de874
commit 63e0cbc0a4
2 changed files with 13 additions and 9 deletions

View File

@@ -401,10 +401,6 @@ export const TVJellyseerrSearchResults: React.FC<
}) => {
const { t } = useTranslation();
const hasMovies = movieResults && movieResults.length > 0;
const hasTv = tvResults && tvResults.length > 0;
const hasPersons = personResults && personResults.length > 0;
if (loading) {
return null;
}
@@ -431,22 +427,26 @@ export const TVJellyseerrSearchResults: React.FC<
return (
<View>
{/* No section requests `hasTVPreferredFocus`: the native search field
keeps focus while typing, otherwise the first result would re-grab
focus on every keystroke as results re-render. The user navigates
down to the grid manually. */}
<TVJellyseerrMovieSection
title={t("search.request_movies")}
items={movieResults}
isFirstSection={hasMovies}
isFirstSection={false}
onItemPress={onMoviePress}
/>
<TVJellyseerrTvSection
title={t("search.request_series")}
items={tvResults}
isFirstSection={!hasMovies && hasTv}
isFirstSection={false}
onItemPress={onTvPress}
/>
<TVJellyseerrPersonSection
title={t("search.actors")}
items={personResults}
isFirstSection={!hasMovies && !hasTv && hasPersons}
isFirstSection={false}
onItemPress={onPersonPress}
/>
</View>

View File

@@ -280,13 +280,17 @@ export const TVSearchPage: React.FC<TVSearchPageProps> = ({
{/* Library Search Results */}
{isLibraryMode && !loading && (
<View style={{ gap: SECTION_GAP }}>
{sections.map((section, index) => (
{sections.map((section) => (
<TVSearchSection
key={section.key}
title={section.title}
items={section.items!}
orientation={section.orientation || "vertical"}
isFirstSection={index === 0}
// Never auto-focus a result. The native search field owns focus
// while typing; `hasTVPreferredFocus` here would re-grab focus on
// every keystroke as results re-render. User navigates down to the
// grid manually.
isFirstSection={false}
onItemPress={onItemPress}
onItemLongPress={onItemLongPress}
imageUrlGetter={