@marketdataapp/ui

Shared component library for MarketData properties

Typography

font-sans

The quick brown fox jumps over the lazy dog.

font-mono

The quick brown fox jumps over the lazy dog.

font-quicksand

The quick brown fox jumps over the lazy dog.

Brand Colors

lightorange
#FFDFB9
darkorange
#E83155
lightblue
#0085f2
darkblue
#003286
bluebg
#001A6C

Semantic Colors

Token triplets (background / border / text) for each admonition type, with dedicated dark variants. See the Admonitions section below for the rendered component.

Note
bg border text darkbg darkborder darktext
Tip
Info
Warning
Danger

Admonitions

Docusaurus-style callout boxes. Five built-in types, each with its own icon (sourced from Docusaurus). Supports custom titles, multiple paragraphs, links, inline code, lists, and more.

Default Types

Each type uses its semantic color tokens for background, left border, and text — and ships with the matching SVG icon.

Note

Some content with Markdown syntax. Check this api.

Tip

Some content with Markdown syntax. Check this api.

Info

Some content with Markdown syntax. Check this api.

Warning

Some content with Markdown syntax. Check this api.

Danger

Some content with Markdown syntax. Check this api.

Custom Titles

Replace the default label with anything — including markdown formatting. Mirrors the Docusaurus :::tip[Custom Title] syntax.

Pro Tip!

You can rate-limit your requests with the X-Api-Ratelimit-Reset header — no need to poll.

Did you know?

Our real-time data feeds use the same NMS-distributed sources as the major exchanges.

Heads up — rate limit changes

Free-tier requests are capped at 100/day starting in May.

Rich Content

Multiple paragraphs, ordered/unordered lists, inline code, and links all flow naturally inside .admonition-content.

Migrating from v3

Upgrading the SDK from v3 to v4 is mostly a drop-in replacement, but there are a few breaking changes you should know about.

The most common migration steps:

  1. Replace marketdata.client(key) with new MarketData({ apiKey: key }).
  2. Switch from positional arguments to keyword options on every endpoint.
  3. Update error handling — exceptions are now MarketDataError subclasses rather than plain Error.

For the full diff, see the migration guide.

Don’t commit your API key

If your API key ever ends up in a public repo, rotate it immediately:

  • Open your API Keys page.
  • Click Revoke on the leaked key.
  • Generate a new one and update your environment variables.

Leaked keys can be abused before our anomaly detection catches the spike — rotation is always faster than recovery.

Without an Icon

Omit .admonition-icon for a text-only heading. Drop the heading entirely if you only need the colored container.

Note

An admonition heading without the leading icon — title text only.

Tip: A bare admonition with no heading at all — just the colored container around inline content. Useful for short asides where the visual treatment is enough context.

Markup Pattern

<div class="admonition admonition-tip">
  <div class="admonition-heading">
    <span class="admonition-icon"></span>
    <span>Pro Tip!</span>
  </div>
  <div class="admonition-content">
    <p>Some <strong>content</strong> with <a href="...">a link</a>.</p>
  </div>
</div>
.admonition .admonition-note .admonition-tip .admonition-info .admonition-warning .admonition-danger .admonition-heading .admonition-icon .admonition-content

Gradients & Shadows

bg-gradient-orange
bg-gradient-blue
shadow-line
shadow-darkline
shadow-diffuse

Buttons

Hover to see gradient transitions. All buttons include disabled states.

.btn-orange-to-blue
.btn-blue-to-orange
.btn-outline-to-orange
.btn-outline-to-blue
.btn-orange-to-outline
.btn-blue-to-outline

Loading state

Primary buttons (.btn-orange-to-blue and .btn-blue-to-orange) automatically render a shimmer effect when HTMX adds the .htmx-request class during an in-flight request, or when you set aria-busy="true" manually. The gradient angle rotates 360° via an animated @property custom property; clicks are blocked (pointer-events: none) so consumers don't double-submit, and the cursor switches to wait.

← click either; random 1–5s

Optional text swap: wrap the default content in [data-btn-default] and add a [data-btn-loading] sibling. CSS hides the first and reveals the second while loading, and the loading span gets inline-flex + a small gap so a .spinner icon sits cleanly next to the text.

<!-- HTMX: zero JS, .htmx-request is added automatically -->
<button class="btn-orange-to-blue" hx-post="/save">
  <span data-btn-default>Save changes</span>
  <span data-btn-loading>
    <span class="spinner w-4 h-4"></span>
    Saving…
  </span>
</button>

<!-- Manual / framework-agnostic via aria-busy -->
button.setAttribute('aria-busy', 'true');   // start
button.removeAttribute('aria-busy');        // done

Spinner

Indeterminate loading indicator. The SVG track + arc live entirely in CSS via mask-image, so consumer markup is just one empty wrapper with role="status" and an sr-only label. Default size is w-8 h-8; override with any Tailwind width/height utility. The arc follows currentColor — set it with any text-* utility. The track defaults to neutral-tertiary; override via the --spinner-track custom property.

Loading...
Loading...
Loading...
Loading...
Loading...
.spinner

Progress Bar

Thin horizontal bar for determinate progress. Two utilities: a .progress-bar track and a .progress-bar-fill child whose width is driven by an inline style="width: N%" (or a CSS custom property). Default height is h-2; override with h-1.5 or h-2.5 on the track for Flowbite small/large sizes. The fill ships in the brand orange gradient by default; modifier classes swap it for the brand blue gradient (-blue) or solid Flowbite semantic colors (-info, -success, -danger) that auto-swap for dark mode. Width changes animate over 400ms so updates from PHP/JS feel smooth.

Default (45%)
Complete (100%)
Small — h-1.5 override (30%)
Large — h-2.5 override (75%)
Brand blue gradient — -blue (60%)
Info — -info (solid Flowbite blue, 50%)
Success — -success (solid Flowbite green, 90%)
Danger — -danger (solid Flowbite red, 15%)

Markup Pattern

<div class="progress-bar" role="progressbar"
     aria-valuenow="45" aria-valuemin="0" aria-valuemax="100">
  <div class="progress-bar-fill" style="width: 45%"></div>
</div>
.progress-bar .progress-bar-fill .progress-bar-fill-blue .progress-bar-fill-info .progress-bar-fill-success .progress-bar-fill-danger

Forms

Account Settings

your display name across MarketData

Please enter a valid email address.

contact support to regenerate

empty + disabled — placeholder is suppressed so the field reads as empty rather than filled

assigned at signup, included in form submissions

contact support to change billing region

Cross-container label state sync

When a <label for="X"> sits in a different parent from #X (e.g. a two-column form grid where labels and inputs live in separate cells), CSS alone can't gray the label when the input is disabled or color it red when the input is aria-invalid="true" — there's no selector that compares a label's for against another element's id. Importing @marketdataapp/ui/label-state-sync and calling initLabelStateSync() reflects each control's state onto its label via disabled and error attributes, which the CSS picks up. Re-syncs automatically as inputs flip or DOM mutates.

The checkbox rows use .form-checkbox-label — a companion-label utility for checkboxes/radios whose input lives in a sibling parent. Unlike .form-label it drops the mb-2 and font-medium stacked-field affordances, and bakes in its own &[disabled] rule so consumer overrides at higher selector specificity can't strip the disabled styling.

data-state-for override for broken for markup

When a <label for="X"> points at an id that doesn't exist — or points at a wrapper around the real controls — add data-state-for="<id> [<id> …]" to the label. The override replaces for as the source for state mirroring (the native for keeps its click-to-focus role even if the id is wrong). Multiple ids combine with ANY semantics: if any listed target is disabled / invalid / focused, the label gets the matching attribute. Common case: amember's swap-input pattern where a <select> and fallback <input> share a single label and toggle visibility with display: none.

Form Classes

.form-container .form-heading .form-label .form-checkbox-label .form-input .form-input-disabled .form-input-error .form-dropdown-input .form-helper-text .form-helper-text-error label[disabled] label[error] data-state-for @marketdataapp/ui/label-state-sync

Copy Input

Readonly input with an overlaid copy-to-clipboard button. Click the button to copy the input's value; success state resets after 2 seconds. Multiple instances on a page operate independently. Pass data-copy-value on the button to copy a value other than the visible text.

Icon-only variant

Tighter footprint — just the icon, with a tooltip on hover. Pair .copy-input-compact with .copy-input-icon-button.

initCopyButton() .copy-input-group .copy-input .copy-input-compact .copy-input-button .copy-input-action .copy-input-icon-button .copy-input-tooltip

Radio Group

Standalone

Radio group on the page background. Uses default contrast tiers.

Select a data plan:

Inside a Form

When nested inside .form-container, backgrounds automatically shift one tier deeper for proper contrast.

Create Account

Select a data plan:

Simple Radio List

Standalone radio buttons without a container, for inline use.

Notification preference:

Inline Radio Buttons

Horizontal radio buttons for compact yes/no or short-option questions.

Enable notifications?
Preferred contact method:

Disabled

Add the disabled attribute — the border lightens, the label dims, and cursor-not-allowed is applied automatically.

.radio-group-container .radio-group-item .radio-button-input .radio-button-helper

Checkboxes

Default

The standard Flowbite checkbox using brand-soft focus ring with full dark-mode support.

Disabled

Add the disabled attribute — the border lightens, the sibling label dims, and cursor-not-allowed is applied automatically.

Inside a Form

Checkboxes work the same inside a .form-container.

Notification Settings

Send me email about:
.checkbox-input

Status Indicators

A coloured dot for system / user / item status. Sized in em so it scales with the parent font-size — drop one into a heading, a paragraph, or a .badge-pill and it adopts the right size. Add .indicator-pulse for an animated halo. The colour carries the meaning, so always pair with an aria-label.

For reliable vertical alignment with its label, wrap the dot and its text in inline-flex items-center gap-2. The bare-inline fallback (vertical-align: middle) aligns to x-height rather than cap-line and drifts noticeably at larger font sizes.

Colours

Operational Degraded Outage Unknown

Pulse

Use the pulse halo when the status is actively changing or warrants extra attention. The halo is a pseudo-element, so screen readers ignore it.

Degraded Outage

Sizes via inheritance

The dot inherits its size from the parent's font-size. .indicator-sm and .indicator-lg nudge it relative to that baseline.

Small text — small dot

Body text — default dot

Larger text — larger dot

.indicator-sm at body size .indicator-lg at body size

Inside a pill

Composes cleanly with .badge-pill.

Operational Degraded Outage
.indicator .indicator-{success|warning|danger|neutral} .indicator-pulse .indicator-{sm|lg}

Badges

Standard Badges

Blue Gray Red Green Yellow Indigo Purple Pink

Pill Badges

Active Pending Expired
.badge .badge-{color} .badge-pill-{color}

Grid Layout

A 12-column grid system. .grid-layout-12 sets up the grid, then child elements use column spans to control width. .grid-content-position and .grid-content-container handle all spacing automatically — they add horizontal margin on small screens to keep content off the viewport edges, then remove it at larger breakpoints where the grid columns provide the centering. Consumers don't need to add their own margin or padding.

The 12-Column Grid

1
2
3
4
5
6
7
8
9
10
11
12

Column Spans

col-span-12
col-span-6
col-span-6
col-span-4
col-span-4
col-span-4
col-span-3
col-span-6
col-span-3
2
2
2
2
2
2

Content Containers

These preset classes center content and progressively narrow it at wider breakpoints. Both include built-in horizontal margin on small screens (mx-4 / md:mx-6) so content never touches the viewport edge. At xl+ the margin is removed because the grid columns handle the inset.

.grid-content-position
span-12 + mx-4 → xl:span-10 + mx-0 → 2xl:span-8 (position + margin only)

.grid-content-container
same centering + margin + card-surface (background, border, padding, shadow, rounded corners)

.grid-layout-12 .grid-content-container .grid-content-position .card-surface

Review Widget

Review platform rating widget. Renders build-time review data with clickable links to the review profile page.

initResenaWidget({ version: 'large' })

Resize below 1024px to see the compact view (text labels hide, only stars + logo remain).

initResenaWidget({ version: 'small' })
initResenaWidget() .resena-widget .resena-small