Krizaka
Documentation
Components

Vertical video

A 9:16 short video with the action rail of a short-video feed — follow, like, comments, share, your own tip button — and the creator's caption over the picture; ShortFeed stacks them as a snap-scrolling feed that plays the one in view.

Web + MobileBetaMedia

Web and mobile — the same component for React and React Native. Beta: its API may still change in a minor version.

Why it is here. Used by krizaka.com.

When to use

  • A creator's short clips: a feed, stories, an explore grid that opens on a video.
  • A phone-first product page where the video is the page (Orochia's feed, the home gallery's phone).
  • With tipSlot, topStart (an auction's time left) and aboveCaption (a goal gauge) for what is the product's own.

When not to use

  • For a watch page with a seek bar, subtitles and speed: the full player.Use instead: Video player
  • For a sound without a picture.Use instead: Audio player

Installation

Install

npm install @krizaka/ui @krizaka/tailwind @krizaka/tokens tailwindcss

Styles

@import "tailwindcss";
@import "@krizaka/tailwind";
@import "@krizaka/ui/tailwind.css";

Import

import { VerticalVideo, ShortFeed, verticalVideoLabels } from "@krizaka/ui/vertical-video";

Examples

The rail and the caption

Follow, like, comments, share and a tip button on the right; creator, caption, tags and credit bottom-left.

12.4K
328
95

CamilleAI-generated

The rooftop, the rain, the last take at dawn. #nightshoot #montreal

Original sound — Camille

A feed

ShortFeed: one video per screen, the one in view plays, the next preloads; ↑ ↓ move.

1.2K
48

Camille

Night shoot, part 2.

1.2K
48

Tomás

Sunday market, slow.

Props

ShortFeed

A vertical snap-scrolling feed that plays the video in view, preloads the next and pauses the rest.

PropTypeDefaultDescription
getIdrequired(item: T) => string—A stable key for an item.
itemsrequiredreadonly T[]—The videos, in order.
labelrequiredstring—The feed's accessible name ("Videos"), passed translated.
renderItemrequired(item: T, state: { active: boolean; preload: "none" | "auto" | "metadata"; index: number; }) => ReactNode—One slide: active is true for the one in view, preload for the next, near false for the ones kept empty.
onActiveChange((index: number, item: T) => void)—Called when the slide in view changes.
windownumber1The slides mounted around the one in view (before and after). Default 1; the others keep their height empty.

VerticalVideo

One short video: 9:16, the rail of actions on the right, the creator's caption bottom-left, a progress hairline.

PropTypeDefaultDescription
creatorrequiredVerticalVideoCreator—Who made it: name, portrait, the seal's words.
titlerequiredstring—The video's accessible name ("Video: Night shoot, part 2"), passed translated.
aboveCaptionReactNode—Above the caption: a goal gauge, a challenge's progress.
activebooleantruePlays while true; a ShortFeed passes it for the slide in view. Default true.
captionstring—The caption: collapsed to two lines, expandable when long.
commentsnumber—The comment count under its button.
creditstring—The sound or credit line ("Original sound — Elena").
disclosurestring—A pill beside the name: "AI-GENERATED" — said on the picture, never only in a page's footnote.
followingbooleanfalseWhether the viewer follows the creator: the "+" on the avatar becomes a check.
labelsPartial<VerticalVideoLabels>—Every word, passed translated.
likedbooleanfalseWhether the viewer likes it: aria-pressed on the like button.
likesnumber—The like count under its button, compact (12.4K) in locale.
localestringenThe locale of the counts. Default en.
loopbooleantruePlays again at the end. Default true.
mutedbooleantrueStarts muted (autoplay needs it). Default true.
onComment(() => void)—Opens the comments; without it the button still shows.
onFollow((following: boolean) => void)—The viewer follows or unfollows; without it the avatar has no "+".
onLike((liked: boolean) => void)—The viewer likes or unlikes (the button, L, a double tap).
onMore(() => void)—The "more" button's action (report, hide); without it the button is not drawn.
onShare(() => void)—Opens the share sheet.
posterstring—The picture until the first frame, and under reduced motion.
preload"none" | "auto" | "metadata"metadataThe next slide's: auto loads it ahead, none waits. Default metadata.
sharesnumber—The share count under its button.
srcstring—The clip — absent, the poster alone shows (MP4 or WebM; an HLS address only in Safari — use the player of @krizaka/ui/video-player for HLS).
tagsreadonly string[][]Tags under the caption (without #).
tipSlotReactNode—The product's own action on the rail: a tip, an unlock — a button of yours (≥ 44 px, named).
topStartReactNode—Top left: a chip over the picture (an auction's time left).

Accessibility

  • Each video is an article named by title; the picture is one button (tap to pause or play, double tap to like) and the rail a named group.
  • The progress hairline is a progressbar named by its label.
  • Under reduced motion nothing autoplays: the poster and a play button; the like heart shows without growing.
  • Over the picture everything reads on scrim and fg-on-media, which do not change with the theme.

Keyboard

KeysAction
Space / KPlay or pause the focused video.
LLike it.
Arrow Up / Arrow DownIn a feed: the previous or next video, the focus follows.
TabThe tap target, then the rail's buttons, then the caption's “More”.

Best practices

  • Give every word in labels and a title that names the clip; the rail's buttons are named, 44 px and say their state (aria-pressed).
  • Counts are compact in the viewer's locale (12.4K): pass numbers, not strings.
  • In a ShortFeed, pass active and preload from renderItem: the one in view plays, the next preloads, the rest pause and stay unmounted.
  • Put product actions in slots, never a fork: a tip, an unlock, a report.

Generated from the code of @krizaka/ui 3.8.0: its meta.ts, its examples and its types.Edit this documentation on GitHub

On this page