Actions Core Stable
FollowButton
A follow toggle that shows the result at once, then commits when the server agrees or rolls back and says so, with the width held steady across every label
Available for Svelte 5, React, and Vue 3.
Preview
svelte
<script lang="ts">
import { FollowButton } from "fancy-ui-svelte";
let following = $state(false);
</script>
<FollowButton sound bind:following label="Follow Rama" />Installation
pnpm add fancy-ui-svelte
import { FollowButton } from "fancy-ui-svelte";
Usage
svelte
<script lang="ts">
import { FollowButton } from "fancy-ui-svelte";
let following = $state(false);
</script>
<FollowButton sound bind:following label="Follow Rama" />Examples
Basic Usage
A bindable toggle that commits at once when nothing needs to be awaited.
svelte
<script lang="ts">
import { FollowButton } from "$lib/fancy-ui/follow-button";
let following = $state(false);
</script>
<FollowButton sound bind:following label="Follow Rama" />Async Server
A fake 800 ms server and a switch that makes the next request fail: watch the optimistic flip, the rollback, and the retry.
svelte
<script lang="ts">
import { FollowButton } from "$lib/fancy-ui/follow-button";
import { Switch } from "$lib/fancy-ui/switch";
let following = $state(false);
let failNext = $state(false);
// A fake server: every request takes 800 ms. With the switch on, the next one
// is refused (and the switch turns itself off), so the rollback and the retry
// can both be watched.
async function onToggle(_next: boolean) {
// Read and consume the flag when the request STARTS: a request sent under
// "Fail next request" fails even if the switch is turned off meanwhile.
const refuse = failNext;
failNext = false;
await new Promise((resolve) => setTimeout(resolve, 800));
if (refuse) throw new Error("The server said no");
}
</script>
<div class="flex flex-col items-center gap-4">
<FollowButton sound bind:following {onToggle} label="Follow Rama" />
<Switch bind:checked={failNext}>Fail next request</Switch>
</div>Props
| Prop | Type | Default | Description |
|---|---|---|---|
following | boolean | false | Whether the viewer follows (bindable). The committed value is written back when onToggle resolves, never before; a write from the parent while an attempt is pending wins and drops that attempt |
onToggle | (next: boolean) => void | Promise<unknown> | - | Called with the value the click asks for. Return nothing to commit at once, or a promise: resolve commits, reject (or throw) rolls back, shows the error and announces it. Clicking again retries |
onFollowingChange | (following: boolean) => void | - | Called with the committed value, once per successful attempt; not called for a rolled-back or superseded one |
label | string | - | Stable accessible name, e.g. "Follow Rama"; it never changes with the visible text. Defaults to the idle label |
labels | { follow?: string; following?: string; unfollow?: string } | { follow: "Follow", following: "Following", unfollow: "Unfollow" } | Visible text per state. The unfollow text is previewed on hover or keyboard focus of a fine pointer, never on touch |
errorLabel | string | "Try again" | Visible text and assertive announcement after a failed attempt |
resetMs | number | 2000 | How long the error state holds before reverting, in milliseconds |
variant | ButtonVariant | - | Button variant. Left unset, the idle state is "primary" and the following state "outline" |
size | ButtonSize | "md" | Passed straight through to the underlying Button |
disabled | boolean | false | Disables the button and blocks the toggle |
iconOnly | boolean | false | Drops the visible text, keeping the accessible name |
onclick | (event: MouseEvent) => void | - | Click handler, called right after the toggle starts; never called while disabled or pending |
class | string | - | Additional CSS classes |
ref | HTMLButtonElement | HTMLAnchorElement | null | null | Bindable element reference, matching Button's own ref type |
sound | boolean | false | Plays toggle-on or toggle-off on a committed change and error on a failed one, with the error vibration, once the user has enabled sound |
Links
Related components
Button
The foundational push-button: six variants, three sizes, a loading state, and a polymorphic href/anchor mode
Actions Core
ButtonGroup
Joins a row of adjacent actions into one seamless control — one border, one divider, no doubled edges
Actions Core
CopyButton
Button preset wired to the clipboard, morphing its icon and label to a success or failure state for a moment after each copy attempt
Actions Core