Componentmedia0.83 KB gzipZero dependencies
Crosshair Picker
Reticle style grid with live preview.
Preview
Live Preview
Crosshair
Installation
Tokens guide →Add to your project via CLI (zero dependencies, code you own):
npx bigbullui add crosshair-pickerOr install the full npm package:
npm install bigbulluiUsage
Open in StackBlitzimport { CrosshairPicker } from "@/components/ui/crosshair-picker";
<CrosshairPicker />Usage guidance
Use Crosshair Picker when a ticket stub surface needs Reticle style grid with live preview. Keep props minimal and prefer composition with sibling stubs.
Avoid Crosshair Picker for long form flows or dense data grids where a dedicated layout block fits better.
Source code
crosshair-picker.tsxZero dependencies (only React + utils). Copy and paste directly into your project:
"use client";
import * as React from "react";
import { cn } from "./lib/utils";
export interface CrosshairPickerProps extends React.HTMLAttributes<HTMLDivElement> {
value?: string;
onPick?: (id: string) => void;
}
const STYLES = [
{ id: "cross", glyph: "+", label: "Cross" },
{ id: "dot", glyph: "•", label: "Dot" },
{ id: "circle", glyph: "○", label: "Circle" },
{ id: "x", glyph: "×", label: "X mark" },
];
/** Crosshair picker: reticle style grid with live preview. */
export function CrosshairPicker({ value = "cross", onPick, className, ...props }: CrosshairPickerProps) {
const [sel, setSel] = React.useState(value);
return (
<div role="radiogroup" aria-label="Crosshair style" className={cn("w-full touch-none select-none rounded-md border border-dashed border-border bg-card p-2.5", className)} style={{ touchAction: "none" }} {...props}>
<p className="font-mono text-[10px] font-bold uppercase tracking-[0.2em] text-muted-foreground">Crosshair</p>
<div className="mt-2 grid grid-cols-4 gap-1.5">
{STYLES.map((s) => (
<button
key={s.id}
type="button"
role="radio"
aria-checked={sel === s.id}
aria-label={s.label}
onClick={() => {
setSel(s.id);
onPick?.(s.id);
}}
className={cn(
"flex min-h-11 touch-none items-center justify-center rounded-md border-2 font-mono text-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
sel === s.id ? "border-accent bg-accent/10 text-foreground" : "border-border bg-background text-muted-foreground"
)}
style={{ touchAction: "none" }}
>
{s.glyph}
</button>
))}
</div>
</div>
);
}