By ISOMORPH
Strapi v5 custom field that replaces the usual patchwork of enum plus optional relations plus string fields with a single link picker.
released July 21, 2026
npm install @isomorph-agency/strapi-plugin-linkStrapi 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.
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 }.
@isomorph-agency/link-resolver works with Next.js, Nuxt, Astro, anythingfr, en)npm install @isomorph-agency/strapi-plugin-linkEnable 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",
},
},
});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.
npm install @isomorph-agency/link-resolverimport { 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).
{
"kind": "internal",
"internal": {
"contentTypeUid": "api::service.service",
"documentId": "xyz",
"titleSnapshot": "Toiture"
},
"label": "Voir nos services toiture",
"newTab": false
}git clone git@github.com:agenceisomorph/strapi-plugin-link.git
cd strapi-plugin-link
npm install
npm run build
npm testLink to a local Strapi project :
cd /path/to/your/strapi/project
npm install file:/absolute/path/to/strapi-plugin-linkMIT © ISOMORPH
Share your work with the community and get it listed in the Strapi ecosystem for everyone to discover and use.
Submit
