sittari-studio

link field

by sittari-studio
payload-plugins
Custom fields
v4
^4.0.0-0
MIT

Overview

Summary generated from the README

Adds a reusable link field to Payload collections, with a Lexical editor feature that shares the same value shape. A plugin resolves internal document URLs through a configurable callback. It includes admin styles, HTML converters and React JSX converters for frontend rendering. Targets Payload 4.

Features

  • linkField helper with drawer appearance, relationTo collections and optional localized labels
  • Lexical LinkFieldFeature replacing Payload's native link feature
  • resolveDocumentUrl callback to build URLs for internal documents
  • HTML converters for Payload v4 Lexical-to-HTML conversion
  • React JSX converter with custom renderer support for Next.js Link
  • Lazy normalization of existing native Lexical link nodes

Use cases

  • Add internal or external link fields to pages with relationships to pages and posts
  • Replace the default Lexical link feature with document-aware links in rich text
  • Render rich text links with Next.js Link and analytics through a custom renderer

From the author

PayloadCMS link-field plugin.

Installation

npm i @sittari/payload-link-field

0

Stars

0

Forks

0

Open Issues

1 months ago

Last Updated

0

Weekly Downloads

v0.4.1

npm Version

197.3 KB

Unpacked Size

1

Dependencies

Repository stars

Trends appear after 7 days of data. Daily snapshots have not started yet.

Shared by 8 plugins in sittari-studio/payload-plugins.

npm weekly downloads

Trends appear after 7 days of data. Daily snapshots have not started yet.

Each point is npm's rolling 7-day download count.

Health Score

55/100Good

Composite score based on GitHub activity, stars, npm downloads, publish recency, dependency count, and package size.

Badge for your README

Payload Directory health badge
Markdown
[![Payload Directory](https://payloaddirectory.dev/badge/1294311885-link-field.svg)](https://payloaddirectory.dev/plugins/1294311885-link-field)
HTML
<a href="https://payloaddirectory.dev/plugins/1294311885-link-field"><img src="https://payloaddirectory.dev/badge/1294311885-link-field.svg" alt="Payload Directory"></a>
Updated Sep 11, 2026Created Jul 8, 2026Published Sep 11, 2026

README

PayloadCMS link-field plugin.

Install

pnpm add @sittari/payload-link-field

Usage

Import the admin stylesheet from your Payload admin CSS file:

@import '@sittari/payload-link-field/admin.css';
import { buildConfig } from 'payload';
import { linkField, linkFieldPlugin } from '@sittari/payload-link-field';

export default buildConfig({
  plugins: [
    linkFieldPlugin({
      resolveDocumentUrl: ({ collectionSlug, document }) => {
        if (collectionSlug === 'pages' && typeof document?.slug === 'string') {
          return `/${document.slug}`;
        }

        return null;
      },
    }),
  ],
  collections: [
    {
      slug: 'pages',
      fields: [
        {
          name: 'title',
          type: 'text',
        },
        linkField({
          name: 'link',
          label: 'Link',
          appearance: 'drawer',
          relationTo: ['pages', 'posts'],
          localizeLabel: true,
        }),
      ],
    },
  ],
});

localizeLabel controls whether the link's nested label field is localized. It defaults to true; set it to false when link labels should use one value across all locales.

LinkFieldFeature() uses the same field schema and value shape as linkField(). It must replace Payload's native feature (both features use the link key), and linkFieldPlugin() remains required because it registers resolveDocumentUrl for reads and serialization.

import { lexicalEditor } from '@payloadcms/richtext-lexical';
import { LinkFieldFeature } from '@sittari/payload-link-field';

const editor = lexicalEditor({
  features: ({ defaultFeatures }) => [
    ...defaultFeatures.filter((feature) => feature.key !== 'link'),
    LinkFieldFeature({
      relationTo: ['pages', 'posts'],
    }),
  ],
});

The feature accepts defaultType, relationTo, showLabel, and showNewTab. When relationTo is omitted, all non-internal collections are considered and collections the current admin user cannot read are removed from the relationship selector. Collections whose slugs start with payload- are always discarded, including when explicitly provided. Existing Payload-native custom and internal link nodes are normalized lazily when read or opened in the editor; their next save writes only the plugin-owned field shape.

Payload v4 HTML conversion requires custom node converters to be passed explicitly:

import {
  convertLexicalToHTMLAsync,
  defaultHTMLConvertersAsync,
} from '@payloadcms/richtext-lexical/html-async';
import { LinkFieldHTMLConverters } from '@sittari/payload-link-field';

const html = await convertLexicalToHTMLAsync({
  converters: {
    ...defaultHTMLConvertersAsync,
    ...LinkFieldHTMLConverters,
  },
  data,
});

Frontend rendering

The React export provides JSX converters for Payload's RichText component and is safe to import from React Server Components. Spread the plugin converters after Payload's defaults:

import { RichText } from '@payloadcms/richtext-lexical/react';
import { LinkFieldJSXConverter } from '@sittari/payload-link-field/react';

export const Content = ({ data }) => (
  <RichText
    converters={({ defaultConverters }) => ({
      ...defaultConverters,
      ...LinkFieldJSXConverter(),
    })}
    data={data}
  />
);

The spread order intentionally replaces Payload's default link and autolink converters. The converter renders only a populated fields.url; unresolved links preserve their formatted children without rendering an anchor or falling back to customUrl.

Pass a renderer to integrate Next.js Link, analytics, or custom routing. The renderer receives normalized fields, rendered children, url, newTab, and the untouched serialized node:

import Link from 'next/link';
import { LinkFieldJSXConverter } from '@sittari/payload-link-field/react';

const converters = LinkFieldJSXConverter({
  renderer: ({ children, newTab, url }) => (
    <Link
      href={url}
      rel={newTab ? 'noopener noreferrer' : undefined}
      target={newTab ? '_blank' : undefined}
    >
      {children}
    </Link>
  ),
});

Similar plugins

link field — Payload Directory