Skip to main content

Overview

Toggle elements provide simple on/off controls. They’re perfect for enabling/disabling features or choosing between two states.
ElementUse CaseReturns
switchEnable/disable featuresboolean
linkBehaviorEmbed vs. direct link (Linktree-specific)'embedLabel' | 'linkOffLabel'

Switch Toggle

Boolean toggle for enabling/disabling features. Provides a visual on/off switch UI.

Properties

PropertyTypeDescription
idstringUnique identifier (becomes prop name)
inputType'switch'Must be 'switch'
titlestringField title
descriptionstringHelp text
labelstringLabel text next to switch
defaultValuebooleanInitial state (true = on, false = off)
validationobjectValidation rules

Validation

RuleTypeDescription
requiredbooleanSwitch must be ON (value must be true)
Setting required: true means the switch must be ON. This is useful for terms acceptance or required opt-ins. Most switches should not be required.

Example

linkapp.config.ts
{
  id: "showTitle",
  inputType: "switch",
  title: "Display Options",
  description: "Toggle title visibility",
  label: "Show title",
  defaultValue: true,
  validation: {
    required: false  // Optional - can be on or off
  }
}

Usage in Layout

app/expanded.tsx
type Settings = {
  showTitle: boolean
}

export default function ClassicLayout({ showTitle }: AppProps<Settings>) {
  return (
    <div>
      {showTitle && <h1>My LinkApp</h1>}
      <p>Content</p>
    </div>
  )
}

Common Patterns

Feature toggle:
{
  id: "enableNotifications",
  inputType: "switch",
  title: "Notifications",
  label: "Enable email notifications",
  defaultValue: false
}
Display option:
{
  id: "showDescription",
  inputType: "switch",
  title: "Display Options",
  description: "Show or hide the description text",
  label: "Show description",
  defaultValue: true
}
Required acceptance:
{
  id: "agreeToTerms",
  inputType: "switch",
  title: "Terms of Service",
  description: "You must accept the terms to continue",
  label: "I agree to the Terms of Service",
  defaultValue: false,
  validation: {
    required: true  // Must be ON
  }
}
Privacy setting:
{
  id: "publicProfile",
  inputType: "switch",
  title: "Privacy",
  description: "Make your profile visible to everyone",
  label: "Public profile",
  defaultValue: false
}

Multiple Switches

Group related switches under one title:
elements: [
  {
    id: "showTitle",
    inputType: "switch",
    title: "Display Options",  // Section title
    description: "Control what appears on your LinkApp",
    label: "Show title",
    defaultValue: true
  },
  {
    id: "showDescription",
    inputType: "switch",
    title: "",  // Same section, no title
    label: "Show description",
    defaultValue: true
  },
  {
    id: "showAuthor",
    inputType: "switch",
    title: "",  // Same section
    label: "Show author name",
    defaultValue: false
  }
]
Usage:
type Settings = {
  showTitle: boolean
  showDescription: boolean
  showAuthor: boolean
}

export default function ClassicLayout({
  showTitle,
  showDescription,
  showAuthor
}: AppProps<Settings>) {
  return (
    <div>
      {showTitle && <h1>Title</h1>}
      {showDescription && <p>Description</p>}
      {showAuthor && <span>By Author</span>}
    </div>
  )
}

Switch vs. Checkbox

When to use switch vs. single checkbox:
Use Switch WhenUse Checkbox When
Enabling/disabling a featureAccepting terms/agreement
Toggling display optionsOpting into something
Turning something on/offConfirming understanding
Immediate effect expectedExplicit consent required
// ✅ Switch - for feature toggle
{ id: "enableDarkMode", inputType: "switch", label: "Enable dark mode" }

// ✅ Checkbox - for acceptance
{ id: "terms", inputType: "checkbox", options: [{ label: "I agree to terms", value: "agreed" }] }
Linktree-specific control for how links behave when clicked. Users choose between showing your LinkApp UI (embed) or navigating directly to the URL (link off).

Properties

PropertyTypeDescription
idstringUnique identifier
inputType'linkBehavior'Must be 'linkBehavior'
titlestringField title
descriptionstringHelp text
labelstringLabel for radio group
defaultValue'embedLabel' | 'linkOffLabel'Initial behavior
linkBehaviorLabelsobjectLabels for the two options
validationobjectValidation rules
PropertyTypeDescription
embedLabelstringLabel for showing LinkApp UI
linkOffLabelstringLabel for direct navigation
Link Behavior lets users choose:
  • Embed (embedLabel): Display your LinkApp’s UI when clicked (renders your layout)
  • Link Off (linkOffLabel): Navigate directly to the URL (bypass your layout)
If not specified, defaults to embedLabel (show your LinkApp).

Example

linkapp.config.ts
{
  id: "linkBehavior",
  inputType: "linkBehavior",
  title: "Link Behavior",
  description: "How should this link behave when clicked?",
  label: "Click behavior",
  defaultValue: "embedLabel",
  linkBehaviorLabels: {
    embedLabel: "Show custom video player",
    linkOffLabel: "Go directly to YouTube"
  },
  validation: {
    required: true
  }
}

Usage in Layout

app/expanded.tsx
type Settings = {
  linkBehavior: 'embedLabel' | 'linkOffLabel'
}

export default function ClassicLayout({
  linkBehavior,
  linkUrl
}: AppProps<Settings>) {
  // If user chose "link off", redirect immediately
  if (linkBehavior === 'linkOffLabel') {
    window.location.href = linkUrl
    return null
  }

  // Otherwise, show your custom UI
  return (
    <div className="custom-video-player">
      <VideoEmbed url={linkUrl} />
    </div>
  )
}

Common Use Cases

Video embed:
{
  id: "videoDisplay",
  inputType: "linkBehavior",
  title: "Video Display",
  description: "Choose how to display YouTube videos",
  linkBehaviorLabels: {
    embedLabel: "Show video player on Linktree",
    linkOffLabel: "Open YouTube in new tab"
  },
  defaultValue: "embedLabel"
}
Content preview:
{
  id: "contentBehavior",
  inputType: "linkBehavior",
  title: "Content Preview",
  linkBehaviorLabels: {
    embedLabel: "Show article preview",
    linkOffLabel: "Go directly to article"
  },
  defaultValue: "embedLabel"
}
Social media:
{
  id: "socialEmbed",
  inputType: "linkBehavior",
  title: "Social Post Display",
  description: "Display Instagram post or link to it",
  linkBehaviorLabels: {
    embedLabel: "Embed Instagram post",
    linkOffLabel: "Open Instagram post"
  },
  defaultValue: "embedLabel"
}

When to Use

Use linkBehavior when: ✅ Your LinkApp embeds or displays content from the URL ✅ Users might want to bypass your UI and go straight to the source ✅ You’re building a media player, content previewer, or social embed Don’t use when: ❌ Your LinkApp doesn’t use the linkUrl at all ❌ Going directly to the URL doesn’t make sense ❌ Your LinkApp is purely decorative

Validation

RuleTypeDescription
requiredbooleanA behavior must be selected
Typically, linkBehavior should have validation: { required: true } so users explicitly choose their preference.

Complete Example

Here’s a video embed LinkApp using both toggle types:
linkapp.config.ts
export default {
  settings: {
    title: "Video Player",
    uses_url: true,  // This app uses the linkUrl prop
    elements: [
      // Link behavior - embed vs. direct link
      {
        id: "linkBehavior",
        inputType: "linkBehavior",
        title: "Link Behavior",
        description: "Choose how videos open",
        linkBehaviorLabels: {
          embedLabel: "Play video in Linktree",
          linkOffLabel: "Open YouTube directly"
        },
        defaultValue: "embedLabel",
        validation: { required: true }
      },

      // Feature switches
      {
        id: "autoplay",
        inputType: "switch",
        title: "Playback Options",
        label: "Autoplay video",
        defaultValue: false
      },
      {
        id: "showControls",
        inputType: "switch",
        title: "",  // Same section
        label: "Show player controls",
        defaultValue: true
      },
      {
        id: "loop",
        inputType: "switch",
        title: "",  // Same section
        label: "Loop video",
        defaultValue: false
      }
    ]
  }
}
Layout implementation:
app/expanded.tsx
type VideoSettings = {
  linkBehavior: 'embedLabel' | 'linkOffLabel'
  autoplay: boolean
  showControls: boolean
  loop: boolean
}

export default function ClassicLayout({
  linkBehavior,
  linkUrl,
  autoplay,
  showControls,
  loop
}: AppProps<VideoSettings>) {
  // Direct link - redirect to YouTube
  if (linkBehavior === 'linkOffLabel') {
    window.location.href = linkUrl
    return null
  }

  // Embed - show custom player
  return (
    <div className="video-player">
      <VideoEmbed
        url={linkUrl}
        autoplay={autoplay}
        controls={showControls}
        loop={loop}
      />
    </div>
  )
}

Best Practices

Use Clear Labels

// ✅ Good - descriptive
{ label: "Enable email notifications" }
{ label: "Show author name and profile picture" }

// ❌ Unclear
{ label: "Notifications" }
{ label: "Author" }

Set Sensible Defaults

// ✅ Good - off by default for optional features
{ id: "betaFeatures", defaultValue: false }

// ✅ Good - on by default for core features
{ id: "showTitle", defaultValue: true }
Use a single title for the group, empty strings for subsequent items:
{
  id: "showTitle",
  title: "Display Options",  // Group title
  label: "Show title"
},
{
  id: "showDate",
  title: "",  // Same group
  label: "Show date"
}
// ✅ Good - tells users exactly what happens
linkBehaviorLabels: {
  embedLabel: "Play video in Linktree",
  linkOffLabel: "Open YouTube in new tab"
}

// ❌ Too generic
linkBehaviorLabels: {
  embedLabel: "Embed",
  linkOffLabel: "Link"
}

Type Safety

Define boolean types for switches:
type MySettings = {
  showTitle: boolean
  enableNotifications: boolean
  autoplay: boolean
  linkBehavior: 'embedLabel' | 'linkOffLabel'
}

export default function ClassicLayout(props: AppProps<MySettings>) {
  // Full type safety ✨
  const { showTitle, enableNotifications, autoplay, linkBehavior } = props

  return <div>...</div>
}

Next Steps