Skip to content
silverpoint
Documentation menu

New in 0.7

Composed components

New in silverpoint 0.7 and reflex-silverpoint-react 0.7. Components drawn on silverpoint's frames and tones: tables, pagination, statistics, collapse panels, and overlays — modal, drawer, popover, tooltip, select, menu and toast — in React, Vue, Angular and Reflex.

Drawn with silverpoint's own pieces

@silverpoint/grounds/ui.css draws its hand-inked frames, hatched tones and heightening on any element that follows its markup contract, so these components are drawn with exactly the same pieces as the first 17. silverpoint 0.8.0 ships them in React, Vue and Angular, on @silverpoint/<framework>/ui/<name> beside the others (38 UI components in all); SpSurface and SpGlyph (sp_surface, sp_glyph) are the building blocks, for components of your own.

Note
The live demos are the Reflex versions of reflex-silverpoint-react 0.8.0: the same @silverpoint/react components, overlays on <dialog> and the Popover API included, and they read silverpoint_provider. Props are snake_case; a string trigger becomes an sp_trigger, a native button that keeps the ARIA the overlay clones onto it.

Every demo on this page follows these controls:

Ground
Substrate
Mode
Palette

sp_surface

The root contract on any element: the ground's class, a hand-drawn frame (control, pill, box, card or round) and a hatched tone (1–4, or a state such as selected or primary). SpSurface reference →

A card frame
A pill, toned 2
Selected
4
tsx
import { SpSurface } from '@silverpoint/react/ui/surface';

<SpSurface frame="card">A card frame</SpSurface>
<SpSurface frame="pill" tone={2}>A pill, toned 2</SpSurface>
<SpSurface frame="control" tone="selected">Selected</SpSurface>
<SpSurface as="span" frame="round" tone={4}>4</SpSurface> {/* as: the HTML tag, div by default */}

sp_glyph

One exact 16×16 mark of UI_GLYPHS — tick, cross, chevrons, arrows, sort marks… — stroked with the text colour, never inked. SpGlyph reference →

tickcrosswarninginfopluschevronDownarrowUpsortellipsis
tsx
import { SpGlyph } from '@silverpoint/react/ui/glyph';

<SpGlyph glyph="tick" />
<SpGlyph glyph="chevronDown" />
<SpGlyph glyph="sort" /> {/* any key of UI_GLYPHS, from '@silverpoint/core/ui' */}

sp_table · sort_rows

Card-framed table: small-caps header, tabular figures, hatched striping, sortable headers with aria-sort. SpTable reference →

On-call teams
Region
CatalogSouth916
ArchiveNorth723
SearchNorth662
BillingEast581
DeliveryWest440
tsx
import { useState } from 'react';
import { uiSortRows } from '@silverpoint/core/ui';
import { SpTable } from '@silverpoint/react/ui/table';

const columns = [
  { key: 'team', title: 'Team', sortable: true },
  { key: 'region', title: 'Region' },
  { key: 'load', title: 'Load %', align: 'end', sortable: true },
  { key: 'incidents', title: 'Incidents', align: 'end', sortable: true },
] as const;

export function Teams({ teams }: { teams: Record<string, unknown>[] }) {
  const [sortKey, setSortKey] = useState('load');
  const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc');
  const sort = (key: string) => {
    setSortOrder(key === sortKey && sortOrder === 'asc' ? 'desc' : 'asc');
    setSortKey(key);
  };
  return (
    <SpTable
      caption="On-call teams"
      columns={columns}
      data={uiSortRows(teams, sortKey, sortOrder)} // the table draws rows as given
      rowKey="team"
      sortKey={sortKey}
      sortOrder={sortOrder}
      onSort={sort}
      striped
    />
  );
}

sp_pagination

Previous and next, first and last, a window around the current page (heightened); on_change(page). SpPagination reference →

Page 3

tsx
import { useState } from 'react';
import { SpPagination } from '@silverpoint/react/ui/pagination';

export function Pages() {
  const [page, setPage] = useState(3);
  // total: items in all pages; pageSize defaults to 10. onChange receives the page number.
  return <SpPagination total={240} current={page} onChange={setPage} showTotal />;
}

A <nav> of links separated by hairline slashes; the last item is the current page. SpBreadcrumb reference →

tsx
import { SpBreadcrumb } from '@silverpoint/react/ui/breadcrumb';

const trail = [
  { label: 'Docs', href: '/docs' },
  { label: 'Components', href: '/components' },
  { label: 'Composed components', href: '/docs/composed' }, // the last item is the current page
];

<SpBreadcrumb items={trail} />

sp_avatar · sp_avatar_group

A portrait or the person's initials in a drawn round (or square) frame; groups overlap. SpAvatar reference →

tsx
import { SpAvatar, SpAvatarGroup } from '@silverpoint/react/ui/avatar';

<SpAvatar name="Ernesto Crespo" size="lg" /> {/* initials when there is no src */}
<SpAvatar name="Leonardo da Vinci" shape="square" />
<SpAvatar src="/portrait.png" name="Anna Atkins" />
<SpAvatarGroup label="Draughtsmen">
  <SpAvatar name="Albrecht Dürer" size="sm" />
  <SpAvatar name="Raphael Sanzio" size="sm" />
</SpAvatarGroup>

sp_statistic

A small-caps title, a large tabular figure, prefix and suffix, and a trend arrow. SpStatistic reference →

Revenue$48.2k+8.2 %
Churn2.1%−0.4 %
tsx
import { SpStatistic } from '@silverpoint/react/ui/statistic';

<SpStatistic title="Revenue" value="48.2" prefix="$" suffix="k" trend="up" delta="+8.2 %" />
<SpStatistic title="Churn" value="2.1" suffix="%" trend="down" delta="−0.4 %" />

sp_descriptions

A label–value grid (a <dl>), optionally card-framed; one column on narrow containers. SpDescriptions reference →

The release

Ground
silverpoint
Substrate
cream
Charts
60
UI components
38
Palettes
6
License
MIT
tsx
import { SpDescriptions } from '@silverpoint/react/ui/descriptions';

const release = [
  { label: 'Ground', value: 'silverpoint' },
  { label: 'Substrate', value: 'cream' },
  { label: 'Charts', value: '60' },
];

<SpDescriptions title="The release" items={release} columns={3} />

sp_timeline_list

A vertical list of events: done (hatched), current (heightened), pending and error. SpTimelineList reference →

  1. 09:12DrawnThe ground is prepared.
  2. 10:40InkedHatching and heightening.
  3. 11:05ReviewedPrecision mode checked.
  4. —PublishedWaiting for the release.
tsx
import { SpTimelineList } from '@silverpoint/react/ui/timeline-list';

const steps = [
  { title: 'Drawn', time: '09:12', description: 'The ground is prepared.', status: 'done' },
  { title: 'Reviewed', time: '11:05', description: 'Precision mode checked.', status: 'current' },
  { title: 'Published', time: '—', description: 'Waiting for the release.', status: 'pending' },
] as const;

<SpTimelineList items={steps} label="Release steps" />

sp_collapse · sp_collapse_item

Panels that open and close, on native <details>; accordion=True keeps one open. SpCollapse reference →

What is silverpoint?

A fine silver line on a prepared ground.

And cyanotype?

A white line on Prussian blue; tone is its weight.

Precision mode

The inking switched off: exact rules only.

tsx
import { SpCollapse, SpCollapseItem } from '@silverpoint/react/ui/collapse';

<SpCollapse accordion> {/* native exclusive <details name> */}
  <SpCollapseItem title="What is silverpoint?" defaultOpen>
    <p>A fine silver line on a prepared ground.</p>
  </SpCollapseItem>
  <SpCollapseItem title="And cyanotype?">
    <p>A white line on Prussian blue; tone is its weight.</p>
  </SpCollapseItem>
</SpCollapse>

sp_empty

The empty state: a lightly hatched, drawn tray, a line of italic text and actions. SpEmpty reference →

No charts yet

tsx
import { SpButton } from '@silverpoint/react/ui/button';
import { SpEmpty } from '@silverpoint/react/ui/empty';

<SpEmpty description="No charts yet" extra={<SpButton size="sm">Add a chart</SpButton>} />

sp_result

The outcome of an operation: a drawn round mark (tick, info, warning, cross), title and subtitle. SpResult reference →

Published

Every package reached PyPI.

tsx
import { SpButton } from '@silverpoint/react/ui/button';
import { SpResult } from '@silverpoint/react/ui/result';

<SpResult
  status="success" // success, info, warning or error
  title="Published"
  subtitle="Every package reached npm."
  extra={<SpButton size="sm" href="/gallery">Back to the gallery</SpButton>}
/>

sp_textarea

Multi-line text on the SpInput contract: drawn frame, italic placeholder, counter and message. SpTextarea reference →

21 / 120
tsx
import { useState } from 'react';
import { SpTextarea } from '@silverpoint/react/ui/textarea';

export function Note() {
  const [note, setNote] = useState('Drawn in silverpoint.');
  // onChange receives the text, not the DOM event
  return <SpTextarea label="Note" value={note} onChange={setNote} rows={3} maxLength={120} showCount />;
}

sp_input_number

A number field with exact − and + steppers, clamped to min and max; on_change receives the number. SpInputNumber reference →

Value 3

tsx
import { useState } from 'react';
import { SpInputNumber } from '@silverpoint/react/ui/input-number';

export function Copies() {
  const [copies, setCopies] = useState<number | null>(3); // null is an empty field
  return <SpInputNumber label="Copies" value={copies} onChange={setCopies} min={1} max={10} />;
}

A dialog on a card frame over a hatched backdrop: focus trapped, Escape closes it. SpModal reference →

Apply changes

The geometry of the data does not move.

Apply the new ground to every chart on the page?

tsx
import { useState } from 'react';
import { SpButton } from '@silverpoint/react/ui/button';
import { SpModal } from '@silverpoint/react/ui/modal';

export function ApplyChanges() {
  const [open, setOpen] = useState(false);
  return (
    <SpModal
      title="Apply changes"
      description="The geometry of the data does not move."
      trigger={<button type="button">Open the modal</button>} // any element you write
      footer={<SpButton variant="primary" onClick={() => setOpen(false)}>Apply</SpButton>}
      open={open}
      onOpenChange={setOpen}
    >
      <p>Apply the new ground to every chart on the page?</p>
    </SpModal>
  );
}

sp_drawer

The same dialog, sliding in from any edge (side='end', the default, 'start', 'top' or 'bottom'). SpDrawer reference →

Settings

A panel that slides in from any edge, over a hatched backdrop.

tsx
import { SpDrawer } from '@silverpoint/react/ui/drawer';

// side: start, end (the default), top or bottom; uncontrolled here
<SpDrawer title="Settings" side="end" trigger={<button type="button">Open the drawer</button>}>
  <p>A panel that slides in from any edge, over a hatched backdrop.</p>
</SpDrawer>

sp_popover

Anchored content on a card frame, placed by the core on the Popover API; Escape or a click outside closes it. SpPopover reference →

tsx
import { SpPopover } from '@silverpoint/react/ui/popover';

<SpPopover title="About this chart" closable width="260px" trigger={<button type="button">Details</button>}>
  <p>Anchored content, on a card frame. Escape or a click outside closes it.</p>
</SpPopover>

sp_tooltip

A short label shown on hover or keyboard focus, after a delay. SpTooltip reference →

tsx
import { SpTooltip } from '@silverpoint/react/ui/tooltip';

<SpTooltip
  text="Drawn on the ground's own frame" // the trigger's accessible description
  trigger={<button type="button">Hover or focus me</button>}
  side="top"
  delay={300}
/>

sp_select

A single choice with typeahead: the chosen option ticked, the highlighted one heightened. SpSelect reference →

North
East
South
West

Region North

tsx
import { useState } from 'react';
import { SpSelect } from '@silverpoint/react/ui/select';

export function Region() {
  const [region, setRegion] = useState<string | null>('North');
  // items: strings, or { key, label, disabled }; onChange receives the key
  return <SpSelect items={['North', 'East', 'South', 'West']} label="Region" value={region} onChange={setRegion} />;
}

Commands with shortcuts, separators, labels and a danger item; on_select(key). SpDropdownMenu reference →

Last command —

tsx
import { SpDropdownMenu } from '@silverpoint/react/ui/dropdown-menu';

const actions = [
  { type: 'label', key: 'drawing', label: 'Drawing' },
  { key: 'duplicate', label: 'Duplicate', shortcut: '⌘D' },
  { key: 'export', label: 'Export SVG', shortcut: '⌘E' },
  { type: 'separator', key: 'sep' },
  { key: 'delete', label: 'Delete', danger: true },
] as const;

// label names the menu and is the built-in button's text; trigger={…} replaces that button
<SpDropdownMenu label="Actions" items={actions} onSelect={(key) => console.log(key)} />

sp_toast · sp_toaster

Notices that stack in a corner and dismiss themselves; error and warning are announced assertively. SpToast reference →

  1. SavedThe drawing was saved.
tsx
import { useState } from 'react';
import { SpButton } from '@silverpoint/react/ui/button';
import { SpToast, SpToaster } from '@silverpoint/react/ui/toast';

export function Save() {
  const [open, setOpen] = useState(false);
  return (
    <>
      <SpButton onClick={() => setOpen(true)}>Save</SpButton>
      <SpToaster position="bottom-end">
        {/* error and warning are announced assertively; onOpenChange(false) when it closes */}
        <SpToast title="Saved" description="The drawing was saved." kind="success" open={open} onOpenChange={setOpen} />
      </SpToaster>
    </>
  );
}

sp_trigger

The drawn button of every overlay: SpButton's drawing on a native button that keeps the ARIA and the toggle an overlay clones onto it (sp_button does not).

tsx
// React has no trigger component: an overlay's trigger is any element you write,
// cloned with aria-haspopup, aria-expanded and aria-controls.
import { SpButton } from '@silverpoint/react/ui/button';
import { SpPopover } from '@silverpoint/react/ui/popover';

<SpPopover title="Details" trigger={<SpButton>Details</SpButton>}>
  <p>…</p>
</SpPopover>

Surface props

In React, Vue and Angular every component takes ground, substrate, mode, size, palette and id, and reads them from the provider. A value binds as each framework does it (value + onChange, v-model, [(value)] or a forms directive), and an overlay's open state with open + onOpenChange, v-model:open or [(open)] (or defaultOpen).

In Reflex every builder takes ground, substrate, mode, size (sm, md, lg), seed, palette, id, class_name and style. Values and lists (rows, items, options) can be static or state vars. Value components (sp_textarea, sp_input_number, sp_select, sp_pagination) send the new value itself to on_change, never a DOM event. Overlays are controlled with open + on_open_change, or uncontrolled with default_open.