Skip to content

UI components

@media-sdk/ui-react@^0.3.0 provides reusable presentational React components for media search applications. Components render UI from props you pass in — they never call the API, manage search state, or own pagination logic.

bash
pnpm add @media-sdk/ui-react@^0.3.0

Peer dependency: React 18 or 19. @media-sdk/core is installed automatically because prop types reference Photo and Video.

Presentational-only philosophy

@media-sdk/ui-react follows a strict separation of concerns:

LayerResponsibility
Your appData fetching, search state, pagination logic, capability gating, analytics
@media-sdk/reactHooks and provider (useMediaSearch, useMediaVideos, MediaProvider)
@media-sdk/ui-reactUI rendering — props in, JSX out

Components do not:

  • Call searchPhotos, searchVideos, or any MediaClient method
  • Read from MediaProvider context
  • Decide which filters or tabs to show based on provider identity
  • Fetch data on mount or manage internal query state

Your application layer wires hooks to components:

Your app (state + orchestration)

        ├── @media-sdk/ui-react   ← UI rendering (props in, JSX out)

        └── @media-sdk/react      ← hooks, provider


          @media-sdk/core         ← API client, types, cache

This design lets you:

  • Swap providers without changing UI components
  • Replace any component with your own styled version
  • Test UI in isolation with mock data
  • Gate features with useMediaCapabilities in your app, not inside the UI package

Component catalog

ComponentPurpose
SearchBarControlled search input and submit button
MediaTabsPhotos / Videos tab switcher
PhotoGridGrid of photo cards
VideoGridGrid of video cards
PhotoPreviewModal overlay for a selected photo
VideoPreviewModal overlay with video player
PaginationPrevious / next page controls
LoadingStateAccessible loading message
ErrorStateAccessible error message

Lower-level cards (PhotoCard, VideoCard) are used internally by grids and are part of the public API, but most apps compose grids directly.

Full prop tables: Components reference.

Minimal wiring example

tsx
import { useMediaSearch } from "@media-sdk/react";
import {
  SearchBar,
  PhotoGrid,
  Pagination,
  LoadingState,
  ErrorState,
} from "@media-sdk/ui-react";
import { useState } from "react";
import type { Photo } from "@media-sdk/core";

function PhotoBrowser() {
  const [query, setQuery] = useState("");
  const [submittedQuery, setSubmittedQuery] = useState("");
  const [selectedPhoto, setSelectedPhoto] = useState<Photo | null>(null);

  const { data, loading, error, nextPage, previousPage } = useMediaSearch({
    query: submittedQuery,
    enabled: submittedQuery.length > 0,
  });

  return (
    <>
      <SearchBar
        value={query}
        onChange={setQuery}
        onSubmit={(event) => {
          event.preventDefault();
          setSubmittedQuery(query);
        }}
      />

      {loading && <LoadingState message="Loading photos…" />}
      {error && <ErrorState message={error.message} />}

      {data && (
        <>
          <PhotoGrid
            photos={data.items}
            onPhotoSelect={setSelectedPhoto}
          />
          <Pagination
            page={data.pagination.page}
            hasPrevious={data.pagination.hasPrevious}
            hasNext={data.pagination.hasNext}
            loading={loading}
            ariaLabel="Photo results"
            onPrevious={() => void previousPage()}
            onNext={() => void nextPage()}
          />
        </>
      )}
    </>
  );
}

Styling

Components ship with semantic CSS class names (for example search-form, photo-grid, pagination, preview-overlay). Import or override styles in your application. The reference demo at apps/web includes a complete stylesheet.

Public API

ts
import {
  SearchBar,
  MediaTabs,
  PhotoCard,
  PhotoGrid,
  PhotoPreview,
  VideoCard,
  VideoGrid,
  VideoPreview,
  Pagination,
  LoadingState,
  ErrorState,
  type MediaTab,
} from "@media-sdk/ui-react";

Internal utilities such as getPhotoSrc and getPlayableVideoLink are not part of the public API.

Next steps