Media grid
A feed of videos in mixed orientations that never staggers: MediaGrid routes the 9:16 clips to a ShortsShelf (equal-height cards, snap scroll, arrows, “See all”) and lays the others in a uniform 16:9 grid; VideoCard is aspect-aware and gives every card the same body height so rows align.
Web only — React, from @krizaka/ui/media-grid. Beta: its API may still change in a minor version.
Why it is here. Orochia's home feed, Explore and a profile's Videos tab (ORO-HOME-FEED): a Shorts shelf for the 9:16, a uniform grid for the 16:9.
When to use
- A home, an explore page or a profile's Videos tab where creators publish both vertical and horizontal video.
- A gallery whose items come from different sources (
uniform: everything in one frame, the odd one drawn whole over a blurred copy).
When not to use
- For a feed that plays one video per screen.Use instead: Vertical video
- For still photos the owner reorders.Use instead: Photo grid
Installation
Install
npm install @krizaka/ui @krizaka/tailwind @krizaka/tokens tailwindcssStyles
@import "tailwindcss";
@import "@krizaka/tailwind";
@import "@krizaka/ui/tailwind.css";Import
import { MediaGrid, ShortsShelf, VideoCard } from "@krizaka/ui/media-grid";Examples
A feed
Three horizontal clips in the grid, three vertical on the shelf: every card of a row has one height.
Shorts
See all
Free0:12Pouring the mint tea, slow
Camille12.4K views
Free0:12First snow on rue Saint-Denis
Camille12.4K views
Free0:12Desert camp at blue hour
Camille12.4K views
One frame
mode="uniform": vertical clips drawn whole over a blurred copy inside 16:9 cards.

Pouring the mint tea, slow
2.4K views
Backstage, a minute before
2.4K views
First snow on rue Saint-Denis
2.4K views
The unlock in one tap
2.4K views
Props
MediaGrid
A media grid that never mixes heights badly: a shelf for the 9:16, a uniform grid for the rest.
| Prop | Type | Default | Description |
|---|---|---|---|
getIdrequired | (item: T) => string | — | A stable key for an item. |
itemsrequired | readonly T[] | — | The videos, in order. |
orientationOfrequired | (item: T) => VideoCardAspect | — | The source's orientation (from its width and height). |
renderItemrequired | (item: T, state: MediaGridState) => ReactNode | — | One card, drawn in the frame the grid gives (state): use VideoCard. |
shelfrequired | Pick<ShortsShelfProps<unknown>, "title" | "label" | "seeAll" | "previousLabel" | "nextLabel"> | — | The shelf of split: its name, "See all" and arrows, passed translated. |
frame | VideoCardAspect | landscape | The frame of uniform. |
layout | "grid" | "list" | grid | grid or list (one row per video). |
mode | "split" | "uniform" | split | split: verticals on the shelf, the others in the grid · uniform: all in one frame (frame). |
ShortsShelf
A Shorts shelf: equal-height 9:16 cards in a snap-scrolling row.
| Prop | Type | Default | Description |
|---|---|---|---|
getIdrequired | (item: T) => string | — | A stable key for an item. |
itemsrequired | readonly T[] | — | The clips, in order. |
labelrequired | string | — | The shelf's accessible name ("Shorts"), passed translated; shown as its heading unless title is set. |
nextLabelrequired | string | — | The next arrow's name. |
previousLabelrequired | string | — | The arrows' names, passed translated. |
renderItemrequired | (item: T, index: number) => ReactNode | — | One card: use VideoCard aspect="portrait". |
seeAll | { href: string; label: string; linkAs?: LinkComponent; } | — | Opens the vertical feed. |
title | ReactNode | — | A heading different from the name. |
VideoCard
A video card whose frame, body and footer have one height per aspect, so a grid row or a shelf never staggers.
| Prop | Type | Default | Description |
|---|---|---|---|
hrefrequired | string | — | Where the card opens. |
titlerequired | string | — | The title; it names the card and is its link. |
action | ReactNode | — | One quick action at the end of the footer (a tip, a save). Its clicks must not follow the card's link. |
aspect | VideoCardAspect | landscape | The frame: landscape (16:9) or portrait (9:16). |
badges | ReactNode | — | Badges at the top-left of the picture (Free, a price, 18+). Put them on scrim so they read in both themes. |
blurred | boolean | false | A sensitive picture: blurred and scaled so nothing shows (put the reveal button in overlay). |
creator | VideoCardCreator | — | Who made it: name, photo, profile. |
duration | string | — | The length, already formatted (3:42). |
fallback | ReactNode | — | Shown instead of the picture while there is none. |
fit | "cover" | "contain" | cover | cover fills the frame; contain draws the whole picture over a blurred copy of itself (a source of the other
orientation: no cropped face, no black bar). |
layout | "row" | "stack" | stack | stack (picture over text) or row (picture beside the text: the list mode of a section). |
linkAs | LinkComponent | — | The app's router link (Next's Link). |
loading | "eager" | "lazy" | lazy | eager for the first cards of a page. |
meta | ReactNode | — | What is counted (12.4K views), already formatted. |
overlay | ReactNode | — | Over the whole picture, above the card's link (a veil, a reveal button). |
poster | string | null | — | The picture. |
previewSrc | string | null | — | An animated picture (WebP) shown while the card is hovered or focused. |
Accessibility
- The shelf is a labelled section whose row is a list; the arrows are named buttons shown with a mouse, hidden on touch (swipe).
- The card's whole surface is the title's link (a stretched link): no nested interactive element.
- The animated preview plays on hover or focus only.
Keyboard
| Keys | Action |
|---|---|
| Tab | Each card is one link (its title); the creator and the action are their own stops; the shelf takes the focus to scroll with the arrow keys. |
| Arrow Left / Arrow Right | Scrolls the focused shelf. |
Best practices
- Leave
modeonsplitfor a feed: a 9:16 card in a 16:9 grid is what makes a row tower over its neighbours. - Give
orientationOfthe source's width and height, not the card's: a clip of the other shape is drawn withfit="contain", never cropped to a face. - Put what is the product's own in the slots (
badges,action); badges sit onscrimand read in both themes. - Pass every word translated: the shelf's name, its arrows and “See all”.
Related components
Generated from the code of @krizaka/ui 3.18.0: its meta.ts, its examples and its types.Edit this documentation on GitHub
