Skip to content

Helpers and actions

Not everything in the package is a component. These are the functions and actions the components use on each other, exported because they are just as useful in your own code.

Every type mentioned here is written out on the types page.

cn

Merges class names through clsx and tailwind-merge. The second half is the important one: cn('px-2', 'px-8') gives you px-8 rather than two fighting utilities. Every component runs its class prop through this, which is why passing a class always wins.

cn
import { cn } from '@joshicodes/cock';

// Later Tailwind utilities win, so a caller's class beats the default.
cn('px-3 py-2 text-sm', props.class);
cn('rounded-md', isActive && 'bg-accent text-accent-fg');

uid

A counter, not a UUID. It exists for wiring aria-describedby and for attributes together when a component renders several elements that have to refer to each other.

uid
const id = uid();            // ck-1f
const id = uid('field');     // field-1g

<label for={id}>Email</label>
<input {id} aria-describedby="{id}-hint" />

Ids are per page load, so do not put one in a database or a URL. In a server-rendered page the counter starts again on the client; the components only use ids for attributes that are set on the same render, where that does not matter.

lockScroll

Freezes the page behind an overlay and pads the body by the scrollbar width, so the layout does not jump sideways. Reference counted: two open overlays take two locks, and scrolling comes back when the last one lets go.

lockScroll
const release = lockScroll();
// …while the overlay is open
release();

confetti

A canvas burst, drawn in the theme's accent and status colours unless you pass your own. It returns a promise that resolves when the last piece has faded, and it does nothing at all when the visitor has reduced motion turned on — so you can call it without a guard.

Or press Ctrl+Shift+C, which is wired up further down this page with onHotkey.

confetti
confetti();                                   // from the middle of the screen
confetti({ origin: button });                 // from an element
confetti({ origin: { x: 100, y: 400 } });     // from a point

confetti({
	count: 220,
	angle: -70,
	spread: 50,
	velocity: 16,
	gravity: 0.8,
	scale: 1.4,
	colors: ['#f0b429', '#e8590c'],
	duration: 3200
});

ConfettiOptions has the full list. angle is the middle of the cone in degrees, where -90 is straight up and 0 is to the right; gravity and scale are multipliers on the defaults, so 0.5 is half as heavy and half as big.

onHotkey, matchesHotkey, formatHotkey

Shortcuts written as strings: mod+k, shift+/, alt+enter. mod is ⌘ on Apple devices and Ctrl everywhere else, which is the part everybody gets wrong. onHotkey listens on the window and returns its own cleanup; formatHotkey gives you the label to print, like the Ctrl+K on the command palette.

hotkeys
const off = onHotkey('mod+k', () => (open = true));
onDestroy(off);

formatHotkey('mod+k');   // ⌘K on Apple devices, Ctrl+K elsewhere
matchesHotkey(event, 'shift+/');

Actions

Four Svelte actions, used by the overlays and exported for your own. portal moves a node to <body> so no ancestor can clip it, clickOutside closes things, trapFocus keeps Tab inside a dialog and hands focus back on destroy, and anchored positions a panel against a trigger and flips it when the viewport runs out.

actions
<div use:portal>…</div>                     <!-- moved to <body> -->
<div use:portal={'#overlays'}>…</div>

<div use:clickOutside={() => (open = false)}>…</div>
<div use:clickOutside={{ handler: close, ignore: [trigger] }}>…</div>

<div use:trapFocus>…</div>

<div use:anchored={{ to: trigger, placement: 'bottom-start', offset: 8 }}>…</div>

Style fragments

Four strings of Tailwind utilities — focusRing, focusRingInset, disabled and transition — that every component in the kit uses. Reach for them when you write a control of your own and want it to ring and fade like the rest.

style fragments
import { cn, focusRing, transition, disabled } from '@joshicodes/cock';

<button class={cn('rounded-md px-3 py-2', focusRing, transition, disabled)}>

Documented elsewhere

  • theme and accents — the runtime theme object, on theming.
  • toast and toasts — on Toaster.
  • themeScript, themeScriptTag and themeHandle — the no-flash script, in getting started.

cock. Yes, it stands for core component kit. We checked twice.