Skip to content

Display and feedback ​

Components that show information and state without asking the player for input: badges, headline numbers, meters, notices, empty states, tiles, tooltips, icons, map blips and printed documents.

Tone ​

Many components take a tone prop. It is a fixed set of color names, so a component follows the server's theme and you never hard code a color. The type is exported as Tone.

ToneTypical use
neutralDefault, no meaning attached
blueInformation, in progress
greenSuccess, online, valid
redError, danger, expired
amberWarning, pending
violetSpecial, premium
tealAlternate accent
ts
import type { Tone } from '@/kit'

const tone: Tone = 'green'

KNotice and KInfoRow use their own, smaller tone lists (described below) because they express severity or value quality rather than color.

KBadge ​

A small colored pill for a status, count or tag.

KBadge
PropTypeDefaultDescription
labelstring | numbernoneText shown in the badge. The default slot replaces it.
toneTone'neutral'Color of the badge.
iconstringnoneIcon shown before the label.
dotbooleanfalseShows a small colored dot instead of the icon.
size'sm' | 'md''sm'Badge height and text size.

Slots: default replaces the label.

vue
<KBadge tone="green" label="Online" dot />
<KBadge tone="amber" icon="lucide:clock">Pending</KBadge>

KStat ​

One headline number with a label, an optional icon chip and a small hint line.

KStat
PropTypeDefaultDescription
labelstringrequiredSmall caption above the value.
valuestring | numberrequiredThe headline value.
hintstringnoneSmall line under the value.
iconstringnoneIcon shown in a tinted chip on the left.
toneTone'neutral'Color of the icon chip.
monobooleanfalseMonospace value, so money and counts line up.
clickablebooleanfalseRenders a button with a hover state instead of a plain card.

Events: click, fired when the card is a button (clickable).

vue
<KStat label="Sales today" value="$12,480" hint="+8% from yesterday" icon="lucide:banknote" tone="green" mono />

KMeter ​

A percentage bar that turns amber and then red as it drops, for fuel, health, usage and similar.

KMeter
PropTypeDefaultDescription
labelstringrequiredCaption on the left.
valuenumber | nullrequiredPercentage from 0 to 100. null shows N/A with an empty bar.
iconstringnoneIcon before the label.
warnBelownumber50The bar turns amber below this percentage.
badBelownumber25The bar turns red below this percentage.
inversebooleanfalseFor budgets where a full bar is the bad end. Amber and red apply to the remaining headroom instead.
valueTextstringnoneReplaces the percentage shown on the right.
vue
<KMeter label="Fuel" :value="fuel" icon="lucide:fuel" />
<KMeter label="Storage used" :value="86" inverse value-text="860 KB / 1 MB" />

KNotice ​

An inline message box for tips, warnings and errors.

KNotice
PropTypeDefaultDescription
tone'neutral' | 'info' | 'warn' | 'danger''neutral'Severity, which sets the color.
iconstring'lucide:info'Icon shown at the start.

Slots: default is the message text.

vue
<KNotice tone="warn" icon="lucide:triangle-alert">This item is not in the catalog.</KNotice>

KEmpty ​

A centered empty state, also used as a loading state, with an icon, a title, an optional description and room for an action.

KEmpty
PropTypeDefaultDescription
titlestringrequiredMain line.
descriptionstringnoneSmaller explanation under the title.
iconstring'lucide:inbox'Icon in the rounded square.
loadingbooleanfalseReplaces the icon with a spinner.
compactbooleanfalseSmaller icon and less padding.

Slots: default is shown under the text, usually a button.

vue
<KEmpty title="No vehicles" description="You do not own any vehicles yet." icon="lucide:car">
  <KButton label="Browse dealership" />
</KEmpty>

KInfoRow ​

A label and value row for detail panels, with optional icon, monospace value and quality tone.

KInfoRow
PropTypeDefaultDescription
labelstringrequiredText on the left.
valuestring | number | nullnoneText on the right. The default slot replaces it.
iconstringnoneIcon before the label.
monobooleanfalseMonospace value.
tone'default' | 'muted' | 'good' | 'warn' | 'bad''default'Color of the value.

Slots: default replaces the value, for badges or other components.

vue
<KInfoRow label="Plate" value="41KQX882" icon="lucide:hash" mono />
<KInfoRow label="Insurance" value="Active" tone="good" />

KIcon ​

One icon slot for the whole kit. Size it with classes (class="size-6"), the same way you would an Iconify icon.

KIcon
PropTypeDefaultDescription
iconstring | nullnoneWhich icon to draw (see below).

The icon string picks the source by its prefix:

ValueDraws
lucide:carA bundled Iconify icon. Icons are bundled with the kit, so they render in game.
item:waterThe inventory image for that item name, falling back to a placeholder, then a box icon.
vehicle:phantomThe photo for that vehicle model, or a car icon when there is none.
https://example.com/x.pngAny image URL.

Image icons keep their own colors, so text color classes only change Iconify icons.

vue
<KIcon icon="lucide:car" class="size-6" />
<KIcon icon="item:water" class="size-8" />

KTooltip ​

An instant hover tooltip, because the browser's own title tooltip is slow and unstyled in the game.

KTooltip
PropTypeDefaultDescription
textstringrequiredTooltip text. An empty string shows no tooltip.
statestringnoneA current value drawn after the text (On, Open, 42%).
stateTonestring'text-zinc-400'A text color class for the state.
side'top' | 'bottom' | 'right''top'Which side of the content the tooltip appears on.
align'center' | 'start' | 'end''center'For top and bottom tooltips: end lines the tooltip's right edge up with the content, start the left. Use it for controls at a panel edge.

Slots: default is the content the tooltip belongs to.

The tooltip is positioned inside its wrapper, so do not put the wrapper in a container that clips overflow.

vue
<KTooltip text="Sirens" state="On" side="bottom">
  <KButton icon="lucide:siren" />
</KTooltip>

KTile ​

A large square action button for player facing panels (Lock, Enter, Knock).

KTile
PropTypeDefaultDescription
labelstringrequiredMain text.
iconstringrequiredIcon at the top left.
hintstringnoneSmall line under the label.
toneTone'neutral'Color of the tile.
disabledbooleanfalseDims the tile and blocks clicks.
action() => unknownnoneAsync handler. While it runs the tile shows a spinner and is disabled.

Events: click, fired when no action is given. When action is set, it runs instead and click is not emitted.

vue
<KTile label="Lock" icon="lucide:lock" hint="Front door" tone="amber" :action="toggleLock" />
<KTile label="Knock" icon="lucide:hand" tone="blue" @click="knock" />

KSection ​

A titled card that groups related content, with optional actions and collapsing.

KSection
PropTypeDefaultDescription
titlestringnoneHeader text. With no title and no actions slot the header is not drawn.
descriptionstringnoneSmall line under the title.
iconstringnoneIcon before the title.
flatbooleanfalseRemoves the card background and padding.
bodyClassstringnoneExtra classes for the body, for example a grid layout.
collapsiblebooleanfalseThe header becomes a button that opens and closes the body.
defaultOpenbooleantrueInitial state when collapsible.

Slots: default is the body. actions is drawn on the right of the header (clicks on it do not toggle the section).

vue
<KSection title="Advanced" icon="lucide:settings-2" collapsible :default-open="false">
  <template #actions><KBadge tone="blue" label="2" /></template>
  Hidden until the header is clicked.
</KSection>

KScrollRow ​

A single row that scrolls sideways (chips, tabs, button groups) and shows it: the clipped edge fades and a chevron button appears. The mouse wheel scrolls it too. A row that fits looks like a plain flex row.

KScrollRow
PropTypeDefaultDescription
contentClassstringnoneClasses for the row itself, for gap and padding.
stepnumber0.7Fraction of the visible width scrolled per arrow click.

Slots: default is the row content.

vue
<KScrollRow content-class="gap-2">
  <KBadge v-for="tag in tags" :key="tag" :label="tag" size="md" />
</KScrollRow>

KBlip ​

A game map blip: the sprite tinted with the blip color and outlined, as the game draws it. You position it yourself.

Sprite images load from an image host, so a sprite that has not arrived (or fails to load) shows as a plain colored dot, and the previews below depend on your connection.

KBlip
PropTypeDefaultDescription
spritenumberrequiredGame blip sprite id (61 hospital, 60 police station).
colornumber0Game blip color id (1 red, 2 green, 3 blue, 5 yellow). Ignored when tint is set.
tintstring''#rrggbb color that replaces the game color.
sizenumber22Edge of the picture in pixels.
rotnumber0Rotation in game degrees (counter-clockwise from north) for the heading arrow.
headingbooleanfalseDraws the heading arrow on the rim.
alphanumber1Opacity from 0 to 1.
labelstring''Accessible label.

Two helpers are exported alongside it:

FunctionReturns
blipColorHex(color)The #rrggbb color for a game blip color id.
blipSpriteName(sprite)The sprite name for an id. An empty string when the id is unknown.
blipColorHex and blipSpriteName
vue
<KBlip :sprite="61" :color="1" :size="28" label="Hospital" />
<KBlip :sprite="1" tint="#a78bfa" heading :rot="45" />

KIdCard ​

A plastic ID card with the issuer's seal, a photo, monospace values, a barcode strip and a stamp when the document is not valid. It takes one doc object and draws everything as text, so values from players or the database cannot inject markup.

KIdCard
PropTypeDefaultDescription
docDocDatarequiredWhat to print. See below.

DocData fields (shared with KPaperDoc):

FieldTypeDescription
titlestringDocument title. Required.
authoritystringIssuing body shown in the header.
toneToneCard color.
statusstringvalid, expired, suspended and so on. Anything that is not valid gets a stamp.
statusLabelstringText printed on the stamp instead of the status.
photostringImage URL for the portrait.
portraitbooleanSet false to hide the photo box.
namestringHolder name.
nameLabelstringLabel above the name. Defaults to Name.
numberstringDocument or license number.
footerstringLine at the bottom.
fields{ label, value, tone?, wide? }[]Printed fields. tone is muted, good, warn or bad. wide spans both columns.
plate, notes, signaturesUsed by KPaperDoc only.
vue
<KIdCard :doc="{
  title: 'Driver License',
  authority: 'State of San Andreas',
  tone: 'blue',
  status: 'valid',
  name: 'Jordan Reyes',
  number: 'SA-482-7731',
  fields: [{ label: 'Expires', value: '06/02/2031' }]
}" />

KPaperDoc ​

A printed form on a sheet of paper: letterhead with seal, ruled boxes in typewriter type, fine print, signature lines and a state stamp. It suits vehicle papers, rental agreements and permits. It fills the width of its container, so give it a width.

KPaperDoc
PropTypeDefaultDescription
docDocDatarequiredWhat to print. Uses title, authority, tone, status, statusLabel, number, plate, name, nameLabel, fields, notes, signatures and footer.

The paper layout adds three fields to DocData:

FieldTypeDescription
platestringA license plate printed in its own box.
notesstring[]Fine print under the fields, one paragraph each.
signatures{ label, name? }[]Signature lines with an optional signed name.

The stamp is green for valid or active, amber for suspended or grace, and red for any other status. The types DocData, DocFieldData and DocTone are exported.

vue
<KPaperDoc :doc="{
  title: 'Vehicle Registration',
  authority: 'San Andreas Department of Motor Vehicles',
  tone: 'green',
  status: 'valid',
  plate: '41KQX882',
  name: 'Jordan Reyes',
  nameLabel: 'Registered owner',
  fields: [{ label: 'Model', value: 'Sultan RS' }],
  signatures: [{ label: 'Registrar', name: 'D. Whitfield' }]
}" />