Taiwan Stock Quote Card
A Taiwan-convention stock quote card for React: red for up and green for down, limit-up/down locked styling, rolling flashing price digits, a change badge, open/high/low/previous-close cells, a volume bar and a compact 5-level order book — all data supplied via props.
Taiwan's stock market colors run opposite to the international convention — red means up, green means down — and it is one of the easiest localization traps to fall into. This quote card packages the whole Taiwan-board look: red for gains, green for losses, neutral for flat; when the change reaches ±10% (configurable) the price block locks into a solid color with a Limit up (limit up) / Limit down (limit down) badge. The main price rolls digit by digit (on a rise, new digits enter from below), and the card background flashes in the tick's direction on every price change. Below sit open/high/low/previous-close cells, a volume bar, and an expandable 5-level order book — bid bars grow rightward in red, ask bars leftward in green, with the current price on the center line. All data comes in via props; once wired to your feed, just update quote.price.
Bring this into your project
Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.
npx webberui@latest add tw-stock-quote-card.enPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<TwStockQuoteCard/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
Installation
npx webberui@latest add https://webberui.com/r/tw-stock-quote-card.en.jsonOr, once registries are configured in components.json, install it as @webberui/tw-stock-quote-card.
Usage
import { TwStockQuoteCard } from "@/components/ui/tw-stock-quote-card";
<TwStockQuoteCard
quote={{
symbol: "3141",
name: "Fictional Semiconductor", // fictional demo data, not a real company
price: 1085,
prevClose: 1050,
open: 1060,
high: 1090,
low: 1055,
volume: 32180,
time: "13:30:00",
}}
levels={{
bids: [
{ price: 1080, size: 168 },
{ price: 1075, size: 315 },
// ...five levels in total
],
asks: [
{ price: 1085, size: 132 },
{ price: 1090, size: 276 },
// ...five levels in total
],
}}
showLevels
maxVolume={80000}
onPriceChange={(event) => console.log(event.direction, event.price)}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
quote | StockQuote | — | Quote data: symbol, name, current price, previous close, plus optional open/high/low, volume and time |
levels | OrderBookLevels | — | 5-level bid/ask data; shown only together with showLevels |
limitPct | number | 10 | Limit-up/down percentage; the locked styling kicks in when the change reaches ±limitPct |
showLevels | boolean | false | Whether to show the compact 5-level order book |
compact | boolean | false | Compact mode: smaller price type, hides the OHLC cells and the volume row |
maxVolume | number | — | Full scale of the volume bar (in lots); when omitted the bar uses its own volume as full scale (bar is full) |
upColor | string | — | Override the up color (red by default, Taiwan convention); any CSS color string |
downColor | string | — | Override the down color (green by default, Taiwan convention); any CSS color string |
onPriceChange | (event: PriceChangeEvent) => void | — | Callback when price changes; the card background also flashes in the tick's direction |
className | string | — | Forwarded to the outermost container |
StockQuote
| Field | Type | Default | Description |
|---|---|---|---|
symbol | string | — | Ticker symbol |
name | string | — | Stock name |
price | number | — | Current traded price |
prevClose | number | — | Previous close; change and percentage are computed against it |
open | number | — | Opening price (optional) |
high | number | — | Intraday high (optional) |
low | number | — | Intraday low (optional) |
volume | number | — | Volume in lots (Tickets, optional) |
time | string | — | Quote time text (optional) |
OrderBookLevels
| Field | Type | Default | Description |
|---|---|---|---|
bids | OrderBookLevel[] | — | Five bid levels, ideally sorted by price descending (at most the first five are used) |
asks | OrderBookLevel[] | — | Five ask levels, ideally sorted by price ascending (at most the first five are used) |
OrderBookLevel
| Field | Type | Default | Description |
|---|---|---|---|
price | number | — | Order price |
size | number | — | Order size in lots |
PriceChangeEvent
| Field | Type | Default | Description |
|---|---|---|---|
price | number | — | The price after the change |
previous | number | — | The price before the change |
direction | "up" | "down" | — | Direction of the change |
priceTone(change) (resolves the up/down/flat tone), formatTwPrice(value) (zh-TW thousands grouping with two decimals), and the StockQuote, OrderBookLevels, OrderBookLevel, PriceChangeEvent, PriceTone types are also named exports.
How it works
- Red-up/green-down is the Taiwan (and mainland China / Hong Kong) convention, the opposite of US and most international markets. To switch back to the international convention, set
upColorto a green anddownColorto a red (for exampleupColor="#16a34a",downColor="#dc2626"); the tinted backgrounds and order-book bars follow automatically viacolor-mix - When the change (relative to
prevClose) reaches ±limitPct, the card enters the locked state: the price block turns solid and a Limit up (limit up) / Limit down (limit down) badge appears, mirroring Taiwan's daily price limit system (currently 10%) - The component connects to no market feed — all data comes in via props; hook up a WebSocket or polling and updating
quotedrives the digit rolling, the flash and theonPriceChangecallback - Prices are always rendered with zh-TW thousands grouping and two fixed decimals; the rolling digit cells are keyed by their position counted from the right, so when the digit count changes (say 999.95 → 1,000.00) the existing digits keep their cells instead of reshuffling
- The built-in labels (Opening price open, Highest price high, Lowest price low, Previous closing price previous close, Trading volume volume, Buy orders bids, Sell orders asks, Limit up limit up, Limit down limit down) are Traditional Chinese, matching Taiwan quote-board wording
Accessibility
- The whole card is a
role="group"with anaria-labelcontaining the stock name and symbol; the rolling price layer is decorative and hidden witharia-hidden - The current price and change are announced as full text through an
sr-onlyaria-live="polite"region (including the limit-up/limit-down state), so screen readers never miss a price move - The order book's prices and sizes are real text content; the size bars and the center line are decorative and marked
aria-hidden - When the user has "reduce motion" enabled at the system level, the digit rolling, background flash, order-book entrance and bar-growth animations are disabled — states switch instantly while all numeric and color feedback remains
Almanac Day Card
Taiwan almanac day card: big Gregorian date with the lunar date, auspicious do/avoid lists, clash zodiac and lucky hours, with a tear-off page-flip animation between days
CJK Word Count Textarea
A React textarea with CJK-aware counting: switch live between word, character and byte modes, a limit progress ring, near-limit and over-limit warnings, frozen counts while an IME is composing, and an optional hard limit.