Skip to content
Svelte Helpers
Language:en Author:AtomForge

Variant props

Boolean props such as <Button small> read nicely in templates. Inside the component you usually want one value. This chapter shows how to type the props and then collapse them.

flowchart LR
  A["Boolean props: small, compact"] --> B["XOR / AtLeastOne: restrict combinations"]
  B --> C["variantMap: one string value"]

XOR

XOR enforces mutually exclusive prop shapes. It takes two to eight type arguments. Include {} as an argument to allow no variant.

// small OR compact, or neither, but not both
type Props = XOR<{ small: true }, { compact: true }, {}>;

type ButtonProps = XOR<{ primary: true }, { secondary: true }, { ghost: true }, {}>;

Without the {} argument, one of the variants is required.

AtLeastOne

Requires at least one property of an object type, while allowing several.

type LabelOrIcon = AtLeastOne<{ label: string; icon: IconDefinition }>;

Use XOR for "exactly one (or none)", AtLeastOne for "one or more".

variantMap

variantMap takes an object of booleans and a default, and returns the key of the first truthy entry (in object iteration order), or the default.

variantMap({ small: false, compact: true }, "normal"); // "compact"
variantMap({ small: false, compact: false }, "normal"); // "normal"
variantMap({ small: true, compact: true }, "normal"); // "small"

The return type is the union of the keys and the default, for example "small" | "compact" | "normal".

Reactivity

Inside a component, props change over time. Choose deliberately:

import { untrack } from "svelte";

// Captures the initial selection only
const size = untrack(() => variantMap({ small, compact }, "normal"));

// Updates when the props change
const size = $derived(variantMap({ small, compact }, "normal"));

Putting it together

<script lang="ts">
  import { variantMap } from "@atom-forge/svelte-helpers";
  import type { XOR } from "@atom-forge/svelte-helpers";

  type Props = XOR<{ small: true }, { compact: true }, {}>;
  let { small, compact }: Props = $props();

  const size = $derived(variantMap({ small, compact }, "normal"));
</script>

Prerequisites (1)

  • prop-types

Teaches (1)

  • variant-props