Link (universal link picker) logo

Link (universal link picker)

By ISOMORPH

Strapi v5 custom field that replaces the usual patchwork of enum plus optional relations plus string fields with a single link picker.

Latest version

v0.1.1

released July 21, 2026

npm install @isomorph-agency/strapi-plugin-link

@isomorph-agency/strapi-plugin-link

Strapi v5 Custom Field — Universal link picker. One field, all link kinds : internal Content Type references, system pages, external URLs, phone numbers, emails, anchors.

Status: v0.1.0, published on npm (plugin + resolver). Tested on Strapi v5. Full presentation: isomorph.fr/plugins/link.


Why

Strapi v5 has no built-in "link" field. Every project ends up rolling its own — usually a custom component with an enum + 5 optional relations + a long string field. Painful to author, painful to query, painful to migrate.

This plugin gives you one link Custom Field per content. Authors pick a kind, fill one input, done. The shape stored in DB is a stable JSON, and the front gets a tiny resolveLink() helper that returns { href, label, target, rel }.

Features

  • 6 kinds : Internal (any CT), System page, External URL, Phone, Email, Anchor
  • Unified picker — one field, tabbed UI, one summary
  • Slug-safe — internal references survive renaming the target's slug (route resolved by lookup, not stored URL)
  • System pages — declared in plugin config, mapped to fixed routes (Home, Contact, etc. — perfect for Single Types in Strapi)
  • Framework-agnostic front lib — @isomorph-agency/link-resolver works with Next.js, Nuxt, Astro, anything
  • Zod-validated server-side before persistence
  • i18n-ready (admin translations in fr, en)
  • TypeScript strict

Install

npm install @isomorph-agency/strapi-plugin-link

Enable in strapi/config/plugins.ts :

export default ({ env }) => ({
  "@isomorph-agency/strapi-plugin-link": {
    enabled: true,
    config: {
      // Routes URL by Content Type
      contentTypes: {
        "api::page.page": { route: "/:slug" },
        "api::service.service": { route: "/services/:slug" },
        "api::sous-service.sous-service": {
          route: "/services/:service.slug/:slug",
          populateForRoute: ["service"],
        },
        "api::realisation.realisation": {
          route: "/realisations/:categorie.slug/:slug",
          populateForRoute: ["categorie"],
        },
      },
      // System pages (Single Types or hard-coded routes)
      systemRoutes: {
        home: "/",
        contact: "/contact",
        realisations: "/realisations",
        zones: "/zones-intervention",
      },
      telDefaultCountryCode: "+33",
    },
  },
});

Usage in a Strapi component or content type

Add a customField attribute :

{
  "ctaPrimary": {
    "type": "customField",
    "customField": "plugin::link.link",
    "options": {
      "allowedKinds": ["internal", "system", "external", "tel", "mailto"]
    }
  }
}

options.allowedKinds is optional — defaults to all 6 kinds.

Usage on the frontend

npm install @isomorph-agency/link-resolver
import { resolveLink } from "@isomorph-agency/link-resolver";
import { linkConfig } from "@/lib/link-config"; // mirror of strapi config

const link = resolveLink(props.ctaPrimary, linkConfig, populated);
if (link) {
  return <Link href={link.href} target={link.target} rel={link.rel}>{link.label}</Link>;
}

populated is the populated content type entry (only needed for internal kind, to resolve :slug and :relation.slug placeholders).

Stored JSON shape

{
  "kind": "internal",
  "internal": {
    "contentTypeUid": "api::service.service",
    "documentId": "xyz",
    "titleSnapshot": "Toiture"
  },
  "label": "Voir nos services toiture",
  "newTab": false
}

Local dev

git clone git@github.com:agenceisomorph/strapi-plugin-link.git
cd strapi-plugin-link
npm install
npm run build
npm test

Link to a local Strapi project :

cd /path/to/your/strapi/project
npm install file:/absolute/path/to/strapi-plugin-link

License

MIT © ISOMORPH

Submit your content

Share your work with the community and get it listed in the Strapi ecosystem for everyone to discover and use.

Submit
Submit your content