Getting Started with @randsum/ui
Install
Section titled “Install”npm install @randsum/uiIt rolls with @randsum/roller, so a roll in the element follows exactly the
rules a roll in code does. The elements are built with Lit
and carry their own styles in Shadow DOM: there is no stylesheet to import.
Plain HTML, htmx and Astro
Section titled “Plain HTML, htmx and Astro”Import an element once and use its tag. Nothing else is needed, which is why htmx and Astro have no wrapper: an element htmx swaps in upgrades by itself.
<script type="module"> import '@randsum/ui/roller'</script>
<randsum-roller size="compact" notation="2d20H+5"></randsum-roller>
<script> document.querySelector('randsum-roller').addEventListener('randsum-roll', event => { console.log(event.detail.total) })</script>Lists such as presets and keys can be set as JSON attributes, or as
properties from script:
<randsum-roller presets='[{"label":"Advantage","notation":"2d20H"},{"label":"Stats","notation":"4d6L"}]'></randsum-roller>import { Roller } from '@randsum/ui/react/roller'
<Roller size="mini" defaultNotation="4d6L" onRoll={result => console.log(result.total)} />React 18 and 19 both work: the wrapper sets properties and listens for events
itself. notation with onChange keeps the value in your state, and each new
rollSignal rolls on demand.
<script setup>import { ref } from 'vue'import { Roller } from '@randsum/ui/vue/roller'const notation = ref('4d6L')</script>
<template> <Roller size="compact" v-model="notation" @roll="result => console.log(result.total)" /></template>Svelte
Section titled “Svelte”Svelte 5 handles custom elements directly, so there is no wrapper. Import the
element, and @randsum/ui/svelte once for its types:
<script lang="ts"> import '@randsum/ui/roller' import type {} from '@randsum/ui/svelte'</script>
<randsum-roller size="mini" notation="4d6L" onrandsum-roll={e => console.log(e.detail.total)} />React Native and Expo
Section titled “React Native and Expo”React Native has no DOM, so custom elements cannot run there.
@randsum/ui/native/roller is the same roller built from native views, on the
same state, with the same three sizes and the React Roller’s props. It needs
react-native 0.76 or later, and works in Expo as is.
import { Roller } from '@randsum/ui/native/roller'
export function Dice() { return <Roller size="compact" defaultNotation="4d6L" onRoll={result => console.log(result.total)} />}There is no localStorage, so max keeps its history in memory. Pass
onHistoryChange to save each change (to AsyncStorage, say) and
initialHistory to start from what you saved. The colours follow the device’s
light or dark scheme, and RollerThemeProvider changes any token:
import { RollerThemeProvider } from '@randsum/ui/native/theme'
<RollerThemeProvider theme={{ accent: '#0f766e' }}> <Roller size="max" /></RollerThemeProvider>Server rendering
Section titled “Server rendering”Custom elements normally draw themselves once their script runs.
@randsum/ui/ssr renders them on the server instead, with each shadow root
filled in as Declarative Shadow DOM, so the roller is on the page in the first
frame, before any script loads. When the element’s script does run, it swaps
the server copy for the live one in place.
npm install @lit-labs/ssrimport { renderToString } from '@randsum/ui/ssr'
const html = await renderToString( '<randsum-roller size="mini" notation="4d6L"></randsum-roller>')// Send `html` in your page, and load '@randsum/ui/roller' in the browser.It works in any server that runs JavaScript, so an htmx backend can return
rendered rollers in its fragments. In Astro, put the result in
<Fragment set:html={html} />; the rollers on this site are rendered this
way.
Theme it
Section titled “Theme it”Every colour, font and radius is a --rsui-* custom property. Custom
properties inherit through Shadow DOM, so set them on the element or on any
ancestor:
randsum-roller { --rsui-accent: #0f766e; --rsui-radius-md: 4px;}Colours use light-dark(), so set color-scheme on your page and the
elements follow it.
Properties
Section titled “Properties”| Property (attribute) | Type | Notes |
|---|---|---|
size |
'mini' | 'compact' | 'max' |
Defaults to 'compact' |
notation |
string |
Setting it replaces what the user typed |
keys |
readonly Key[] |
Defaults to DEFAULT_KEYS; always shown |
presets |
readonly Preset[] |
Optional named rolls, behind a switch; keys first |
presetsLabel (presets-label) |
string |
What the presets are called. Defaults to “Presets” |
presetsLayout (presets-layout) |
'chips' | 'list' |
Compact: 'list' shows each description |
placeholder |
string |
The empty field’s hint |
appLink (app-link) |
string |
Mini and Compact: a link to the full roller |
history |
boolean |
Max: recent rolls and a History dialog. Defaults to true |
storageKey (storage-key) |
string |
Max: keeps history in localStorage |
historyLimit (history-limit) |
number |
Max: how many rolls history keeps. Defaults to 50 |
Compact also has a footer slot. The element fires randsum-change (detail
{ notation }) on every edit and randsum-roll (detail: the result) after
each roll, and has a roll() method.
The React wrapper takes the same props in camelCase, plus defaultNotation,
onChange, onRoll, rollSignal, footer and className. The Vue wrapper
takes them with v-model for the notation and emits change and roll.
Keys and presets
Section titled “Keys and presets”Every size shows dice keys. Pass keys to change them, and presets to add
named rolls:
import { Roller } from '@randsum/ui/react/roller'import { modifierKeys } from '@randsum/ui/keys'import { modifierPresets } from '@randsum/ui/presets'
<Roller defaultNotation="3d6!" keys={modifierKeys('explode')} presets={modifierPresets('explode')}/>modifierKeys(name) and modifierPresets(name) give each modifier’s own keys
and its documented examples, the same ones on the modifiers page.