Navigation
Actions
Svelte actions from the @codeatlasdev/ui/actions subpath for outside clicks, focus trapping, autofocus, clipboard and long press.
<script>
import { clickOutside, focusTrap, autofocus, clipboard, longpress, keyboardAware, primeKeyboard } from "@codeatlasdev/ui/actions";
</script>
<div use:clickOutside={() => (open = false)}>...</div>
Actions attach behavior to a plain element with use:. They are exported from @codeatlasdev/ui/actions, which keeps them out of the main bundle.
clickOutside
Calls the handler for every click that lands outside the element.
Click inside this area, then click outside.
Outside clicks: 0
Code
<script lang="ts">
import { clickOutside } from '@codeatlasdev/ui/actions';
let count = $state(0);
</script>
<div use:clickOutside={() => count++} class="box">
<p>Click inside this area, then click outside.</p>
</div>
<p class="hint">Outside clicks: {count}</p>
<style>
.box {
padding: 24px;
border-radius: var(--ca-radius-md);
box-shadow: inset 0 0 0 1px var(--ca-outline-subtle);
display: inline-block;
}
.box p, .hint { margin: 0; font-size: var(--ca-font-size-body2); }
.hint { color: var(--ca-text-secondary); align-self: center; }
</style>
focusTrap
Keeps Tab and Shift+Tab inside the element while enabled.
Code
<script lang="ts">
import { Button } from '@codeatlasdev/ui';
import { focusTrap } from '@codeatlasdev/ui/actions';
let open = $state(false);
</script>
<Button onclick={() => (open = true)}>Open trap</Button>
{#if open}
<div use:focusTrap={open} class="trap">
<span>Tab stays inside this box:</span>
<Button variant="outlined">Button A</Button>
<Button variant="outlined">Button B</Button>
<Button variant="outlined" onclick={() => (open = false)}>Close</Button>
</div>
{/if}
<style>
.trap {
flex-basis: 100%;
padding: 20px;
border-radius: var(--ca-radius-md);
box-shadow: inset 0 0 0 1px var(--ca-brand-main);
display: flex;
flex-wrap: wrap;
gap: 12px;
align-items: center;
font-size: var(--ca-font-size-body2);
}
</style>
autofocus
Focuses the element when it mounts.
Code
<script lang="ts">
import { Button } from '@codeatlasdev/ui';
import { autofocus } from '@codeatlasdev/ui/actions';
let key = $state(0);
</script>
<Button onclick={() => key++}>Remount input</Button>
{#key key}
<input use:autofocus placeholder="Focused on mount" class="input" aria-label="Autofocused input" />
{/key}
<style>
.input {
flex-basis: 100%;
padding: 8px 12px;
border-radius: var(--ca-radius-md);
border: 1px solid var(--ca-outline-subtle);
background: transparent;
color: var(--ca-text-primary);
font: inherit;
font-size: var(--ca-font-size-body2);
}
</style>
clipboard
Copies the given text on click and dispatches a copy event.
Code
<script lang="ts">
import { clipboard } from '@codeatlasdev/ui/actions';
let copied = $state(false);
function done() {
copied = true;
setTimeout(() => (copied = false), 2000);
}
</script>
<button use:clipboard={'bun add @codeatlasdev/ui'} oncopy={done} class="btn">
{copied ? 'Copied!' : 'Copy install command'}
</button>
<style>
.btn {
padding: 8px 20px;
border-radius: var(--ca-radius-md);
border: 1px solid var(--ca-outline-subtle);
background: var(--ca-action-hover);
cursor: pointer;
font: inherit;
font-size: var(--ca-font-size-body2);
color: var(--ca-text-primary);
}
</style>
longpress
Dispatches a longpress event after the pointer is held for the given duration.
Code
<script lang="ts">
import { longpress } from '@codeatlasdev/ui/actions';
let fired = $state(false);
function done() {
fired = true;
setTimeout(() => (fired = false), 1500);
}
</script>
<button use:longpress={800} onlongpress={done} class="btn">
{fired ? 'Long press!' : 'Press and hold (800ms)'}
</button>
<style>
.btn {
padding: 12px 24px;
border-radius: var(--ca-radius-md);
border: 1px solid var(--ca-outline-subtle);
background: var(--ca-action-hover);
cursor: pointer;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
font: inherit;
font-size: var(--ca-font-size-body2);
color: var(--ca-text-primary);
}
</style>
Actions
| Prop | Type | Default | Description |
|---|
clickOutside | Action<HTMLElement, () => void> | – | Calls the handler when a click lands outside the element. |
focusTrap | Action<HTMLElement, boolean> | – | Traps Tab focus inside the element while the parameter is true. |
autofocus | Action<HTMLElement, { touch?: boolean } | undefined> | – | Focuses the element on mount without scrolling. On touch devices it only focuses when primeKeyboard() ran in the opening gesture; pass { touch: true } to focus anyway. |
clipboard | Action<HTMLElement, string> | – | Copies the text to the clipboard on click and dispatches a copy CustomEvent with the text as detail. |
longpress | Action<HTMLElement, number> | – | Dispatches a longpress CustomEvent after the pointer is held for the given milliseconds (default 500). |
keyboardAware | Action<HTMLElement> | – | Pads the element's bottom by --ca-kb-inset and scrolls the focused field into view when the on-screen keyboard opens. Use on composers and sticky action bars. |
primeKeyboard | () => void | – | Helper, not an action. Call synchronously in the tap handler that opens a view with an autofocused field so iOS and Android open the on-screen keyboard. No-op with a fine pointer. |
focusTextField | (el: HTMLElement | null | undefined, force?: boolean) => boolean | – | Helper used by autofocus. Focuses the element with a fine pointer, or on touch only after primeKeyboard(). Returns whether it focused. |