@talarion/components
v0.1.0
Published
React components for Talarion prediction market UIs
Maintainers
Readme
@talarion/components
React components for Talarion prediction market UIs. Ships a self-contained MarketCard with CSS-variable theming — no Tailwind required.
Installation
pnpm add @talarion/components reactQuick Start
import { MarketCard, MarketGrid } from "@talarion/components";
import type { Market } from "@talarion/components";
import "@talarion/components/theme.css";
const markets: Market[] = [
{
id: "btc-100k",
title: "Will BTC exceed $100K by end of 2026?",
volume: 1_500_000,
liquidity: 250_000,
outcomes: [
{ label: "Yes", price: 0.65 },
{ label: "No", price: 0.35 },
],
},
];
function App() {
return (
<MarketGrid expectedCount={markets.length}>
{markets.map((m) => (
<MarketCard
key={m.id}
market={m}
onMarketClick={({ market }) => console.log("clicked", market.id)}
onOutcomeClick={({ market, outcome }) =>
console.log(`Trade ${outcome.label} on ${market.title}`)
}
/>
))}
</MarketGrid>
);
}Components
MarketCard
The primary component. Displays a market title, volume/liquidity/outcome stats, and Yes/No outcome buttons.
| Prop | Type | Description |
|------|------|-------------|
| market | Market | Market data to display |
| disabled | boolean? | Disable card and buttons |
| onMarketClick | (event: MarketClickEvent) => void | Card body clicked |
| onOutcomeClick | (event: OutcomeClickEvent) => void | Outcome button clicked |
| className | string? | Additional CSS class |
MarketGrid
Responsive grid container. Uses ResizeObserver to compute column count from available width.
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| children | ReactNode | — | Card elements |
| minCardWidth | number? | 350 | Min card width (px) before columns collapse |
| gap | number? | 16 | Gap between cards (px) |
| expectedCount | number? | — | Limits max columns |
| className | string? | — | Additional CSS class |
StatDisplay
Label + value stat pair with optional highlight color.
OutcomeButtons
Yes/No pill buttons with price in cents. Used internally by MarketCard but exported for standalone use.
MarketRulesModal
Full-screen overlay modal showing settlement rules and resolution date for a market. Closes on backdrop click or the close button.
| Prop | Type | Description |
|------|------|-------------|
| isOpen | boolean | Whether the modal is visible |
| onClose | () => void | Called when the modal should close |
| title | string | Market title shown in the header |
| rules | string? | Settlement / description rules text |
| expirationDate | string? | Expected resolution date (ISO string) |
TalarionLogo
Talarion "T" logo in a circular badge. White by default, clickable (links to talarion.tech).
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| size | number? | 24 | Circle diameter in px |
| clickable | boolean? | true | Render as link to talarion.tech |
| className | string? | — | Additional CSS class |
Integrating MarketCard with MarketRulesModal
The modal is a separate component — wire it up via onMarketClick:
import { useState } from "react";
import { MarketCard, MarketRulesModal, MarketGrid } from "@talarion/components";
import type { Market, MarketClickEvent } from "@talarion/components";
import "@talarion/components/theme.css";
const markets: Market[] = [/* your markets */];
// Extend with rules data your app has available
const rulesMap: Record<string, { rules: string; expirationDate: string }> = {
"btc-100k": {
rules: "Resolves YES if BTC exceeds $100,000 on any major exchange before expiration.",
expirationDate: "2026-12-31",
},
};
function App() {
const [selected, setSelected] = useState<Market | null>(null);
return (
<>
<MarketGrid expectedCount={markets.length}>
{markets.map((m) => (
<MarketCard
key={m.id}
market={m}
onMarketClick={({ market }) => setSelected(market)}
onOutcomeClick={({ outcome }) => console.log(outcome.label)}
/>
))}
</MarketGrid>
{selected && (
<MarketRulesModal
isOpen={!!selected}
onClose={() => setSelected(null)}
title={selected.title}
rules={rulesMap[selected.id]?.rules}
expirationDate={rulesMap[selected.id]?.expirationDate}
/>
)}
</>
);
}Types
interface Market {
id: string;
title: string;
volume: number | null;
liquidity: number | null;
outcomes: MarketOutcome[];
}
interface MarketOutcome {
label: string; // "Yes", "No", "Trump", etc.
price: number; // 0–1 decimal (0.65 = 65¢)
}
interface MarketClickEvent { market: Market }
interface OutcomeClickEvent { market: Market; outcome: MarketOutcome; outcomeIndex: number }Theming
The default theme is dark. Override any --tlr-* CSS variable to customize:
:root {
--tlr-card-bg: #ffffff;
--tlr-card-bg-hover: #f5f5f5;
--tlr-text-primary: #111111;
--tlr-text-tertiary: #777777;
--tlr-success-bg: #f4f7f4;
--tlr-success-text: #4d6b4d;
--tlr-danger-bg: #f8f4f4;
--tlr-danger-text: #8a5555;
/* ... see theme.css for all variables */
}All components carry data-tlr attributes (data-tlr="card", data-tlr="grid") for targeted CSS overrides.
Available Variables
| Variable | Description |
|----------|-------------|
| --tlr-card-bg | Card background |
| --tlr-card-bg-hover | Card hover background |
| --tlr-card-border | Card border color |
| --tlr-card-radius | Card border radius |
| --tlr-card-padding | Card padding |
| --tlr-card-shadow | Card box shadow |
| --tlr-card-shadow-hover | Card hover shadow |
| --tlr-text-primary | Primary text color |
| --tlr-text-tertiary | Tertiary/label text color |
| --tlr-success-bg | Yes button background |
| --tlr-success-text | Yes button text |
| --tlr-success-border | Yes button border |
| --tlr-danger-bg | No button background |
| --tlr-danger-text | No button text |
| --tlr-danger-border | No button border |
| --tlr-btn-radius | Button border radius |
| --tlr-btn-min-width | Button minimum width |
| --tlr-font-family | Font family |
| --tlr-logo-color | Logo fill color |
Utilities
Exported for convenience:
formatVolume(usd: number)—$1.50M,$150.0K,$500formatLiquidity(usd: number)—$1.50M,$150K,$500convertPriceToCents(price: number)—0.65→"65.0"
Docs
Full Talarion documentation at docs.talarion.tech.
License
MIT
