Comic Select
A native select in the comic frame, with the arrow on a starburst that spins on focus.
betaComicSelect.tsx
Examples
Basic
comic-select/basic.tsx
import { ComicSelect } from "@streamuilib/react";
export default function ComicSelectBasic() {
return (
<label className="flex w-full max-w-xs flex-col gap-2">
<span className="font-bold">Pick a power</span>
<ComicSelect defaultValue="">
<option value="" disabled>
Choose one…
</option>
<option value="flight">Flight</option>
<option value="strength">Super strength</option>
<option value="speed">Speed</option>
<option value="invisibility">Invisibility</option>
</ComicSelect>
</label>
);
}Invalid and disabled
comic-select/states.tsx
import { ComicSelect } from "@streamuilib/react";
export default function ComicSelectStates() {
return (
<div className="flex w-full max-w-xs flex-col gap-6">
<label className="flex flex-col gap-2">
<span className="font-bold">Plan</span>
<ComicSelect invalid defaultValue="">
<option value="">Choose a plan…</option>
<option value="free">Free</option>
<option value="pro">Pro</option>
</ComicSelect>
</label>
<label className="flex flex-col gap-2">
<span className="font-bold">Region</span>
<ComicSelect disabled defaultValue="eu">
<option value="eu">Europe</option>
</ComicSelect>
</label>
</div>
);
}Installation
bun add @streamuilib/reactusage.tsx
import { ComicSelect } from "@streamuilib/react";
<ComicSelect aria-label="Power">
<option>Flight</option>
<option>Speed</option>
</ComicSelect>API
| Prop | Type | Default | Description |
|---|---|---|---|
| invalid | boolean | false | Sets aria-invalid and tints the frame pink. |
| frameClassName | string | — | Classes for the outer frame. |
| ...props | ComponentProps<"select"> | — | Every native select attribute; pass <option>s as children. |
Accessibility
- A native <select>: the platform's own picker on phones, typeahead, and full keyboard and screen reader support.
- The starburst arrow is decorative and hidden.
Source
packages/react/src/ComicSelect.tsx
import { ChevronDown } from "lucide-react";
import { cn } from "./cn";
import { comicFrame, halftone } from "./comic";
import { SHAPES } from "./ComicBadge";
import type { SelectProps } from "./Select";
export type ComicSelectProps = SelectProps;
/**
* A comic-book select: a native <select> (the platform's own picker,
* typeahead, full keyboard and screen reader support) in the comic frame,
* with the arrow on a little starburst that spins when the field has focus.
*/
export function ComicSelect({ invalid, frameClassName, className, children, ...props }: ComicSelectProps) {
return (
<div className={comicFrame({ invalid, className: cn("items-center", frameClassName) })} style={halftone(10)}>
<select
aria-invalid={invalid || undefined}
className={cn(
"h-11 w-full min-w-0 cursor-pointer appearance-none bg-transparent pr-12 pl-3 font-semibold focus:outline-none disabled:cursor-not-allowed",
className,
)}
{...props}
>
{children}
</select>
<span aria-hidden className="pointer-events-none absolute right-1.5 grid size-9 place-items-center">
<svg viewBox="0 0 100 100" overflow="visible" className="sui-comic-select-burst absolute inset-0 size-full">
<path d={SHAPES.burst.d} className="fill-lime stroke-ink" strokeWidth={7} strokeLinejoin="round" />
</svg>
<ChevronDown className="relative size-4 text-on-bright" strokeWidth={3} />
</span>
</div>
);
}