An entry point for a back catalogue: three questions score the listening paths, and the winner is handed over as an ordered run of three episodes with cover art, numbers, and a total runtime added up from the episodes themselves.
An entry point for a back catalogue. Three questions score the listening paths, and the winner is handed over as an ordered run of three episodes with cover art, numbers, and a total runtime added up from the episodes themselves.
Free block
This block is free. No license or account is required: install it with the CLI and use it in unlimited projects.
Radix flavor
npx shadcn add "https://ui.beste.co/r/podcast54"Base UI flavor
npx shadcn add "https://ui.beste.co/r-base/podcast54"That installs the block file, the badge6 eyebrow and button1 seal CTA it is built from, and the questionnaire primitive.
import { Podcast54, podcast54Demo } from "@/components/beste/block/podcast54";
export default function Page() {
return <Podcast54 {...podcast54Demo} />;
}import { Podcast54 } from "@/components/beste/block/podcast54";
export default function Page() {
return (
<Podcast54
badge={{ label: "Start here" }}
meta="142 episodes"
heading="Nobody starts a show at episode one"
description="Three questions and we hand you an order to listen in."
shortcuts="numbers"
image={{
src: "https://images.unsplash.com/photo-1478737270239-2f02b77fc618",
alt: "A condenser microphone in a shock mount with a pop filter",
}}
caption="Recorded in one room and published on Tuesdays."
stats={[
{ title: "Median length", value: "38 min" },
{ title: "Published since", value: "2019" },
]}
questions={[
{
name: "reason",
title: "Why are you here?",
choices: [
// what this answer asks a path for
{ value: "craft", label: "I want to get better at the work", traits: ["craft"] },
{ value: "people", label: "I like hearing how people think", traits: ["people"] },
],
},
{
name: "time",
title: "How long is your commute?",
choices: [
{ value: "short", label: "Under half an hour", traits: ["short"] },
{ value: "long", label: "Long enough for a proper one", traits: ["long"] },
],
},
]}
paths={[
{
title: "The one about doing the work",
summary: "Three episodes on process, in the order that makes the third one land.",
traits: ["craft", "short"],
episodes: [
{
number: "31",
title: "The brief nobody reads",
minutes: 34,
note: "Why the document everyone signs is never opened again.",
image: {
src: "https://images.unsplash.com/photo-1590602847861-f357a9332bbc",
alt: "A dynamic microphone on a boom arm against a dark backdrop",
},
},
],
button: { label: "Start with episode 31", href: "https://beste.co" },
},
]}
labels={{ submit: "Build my path", totalLabel: "Three episodes" }}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
badge | Badge | – | Eyebrow above the rule, rendered with Badge6. |
meta | string | – | Short line beside the eyebrow, across the hairline divider. |
heading | string | – | Section heading. |
description | string | – | Section description under the heading. |
questions | PathQuestion[] | [] | The questions, in the order they are asked. |
shortcuts | "letters" | "numbers" | – | Prints a shortcut on every choice of the active question. |
paths | Path[] | [] | Scored against the answers; the highest score wins. |
image | CoverImage | – | Standing photograph beside the questions. |
caption | string | – | Line under the standing photograph. |
stats | { title: string; value: string }[] | [] | Two bordered cells under the photograph. |
labels | Podcast54Labels | {} | Overrides for the buttons, the path heading, and the time units. |
className | string | – | Merged onto the section element. |
type Badge = { label: string };
type ActionButton = { label: string; href: string };
type CoverImage = { src: string; alt: string };
type PathQuestion = {
name: string;
title: string;
description?: string;
choices?: PathChoice[];
multiple?: boolean;
};
type PathChoice = {
value: string;
label: string;
description?: string;
traits?: string[];
};
type Episode = {
number: string;
title: string;
minutes: number;
note: string;
image: CoverImage;
};
type Path = {
title: string;
summary: string;
traits?: string[];
episodes?: Episode[];
button?: ActionButton;
};
type Podcast54Labels = {
previous?: string;
next?: string;
submit?: string;
restart?: string;
pathTitle?: string;
totalLabel?: string;
episodeLabel?: string;
hour?: string;
minute?: string;
};traits, and each path scores the number of them it carries, so a path can win on two of three answers rather than having to match all of them.paths your tie-breaker: put the safest starting point first.number is the episode's own number in the catalogue, so the two never have to agree.minutes keeps the total honest. It is formatted without a locale API, which would risk a server and client mismatch.podcast52
Podcast overview section with cover art, stats grid (episodes, launch date, listeners, awards), and expandable long description. Perfect for show about pages and media kit sections.
podcast41
Searchable episode transcript with clickable timestamps, speaker labels, and download option. Perfect for podcast accessibility features and content discovery.
podcast53
A podcast section with an eyebrow over a hairline rule and a two-column heading, pairing an image tile that floats a live audio player with a divided episode list.
podcast2
Audio player card featuring cover art, animated waveform visualization, play/pause controls, and progress tracking. Perfect for embedded podcast players on show pages.