Skip to content

add new dataAttribute option for placeholders#7468

Merged
bdbch merged 7 commits intodevelopfrom
feature/placeholder-data-attribute-customization
Jan 28, 2026
Merged

add new dataAttribute option for placeholders#7468
bdbch merged 7 commits intodevelopfrom
feature/placeholder-data-attribute-customization

Conversation

@bdbch
Copy link
Member

@bdbch bdbch commented Jan 28, 2026

Changes Overview

Added a new dataAttribute option to the Placeholder extension that allows developers to customize which data attribute name is used for the placeholder label. This provides more flexibility when styling placeholders with custom CSS selectors.

Implementation Approach

  • Added a new dataAttribute option to PlaceholderOptions interface with a default value of 'placeholder'
  • Created a preparePlaceholderAttribute() utility function to sanitize and normalize attribute names:
    • Replaces whitespace with dashes
    • Removes non-alphanumeric characters (except dashes)
    • Removes leading numeric characters and dashes
    • Converts to lowercase
  • Updated the placeholder plugin to use the configured dataAttribute when creating DOM decorations
  • The attribute is prefixed with data- to ensure valid HTML

Testing Done

Added comprehensive unit tests covering:

  • Default behavior (uses data-placeholder when no option is provided)
  • Custom attribute naming (uses provided attribute name)
  • Space-to-dash conversion (automatically converts spaces to dashes for valid HTML attributes)
  • Invalid attribute string repair (sanitizes broken attribute names correctly)

Tests verify that the correct data attribute is applied to empty nodes and that the placeholder text is properly set.

Verification Steps

  1. Configure the Placeholder extension with a custom dataAttribute option: Placeholder.configure({ placeholder: 'Add content...', dataAttribute: 'my-custom-label' })
  2. Inspect the DOM and verify that empty nodes have the data-my-custom-label attribute
  3. Apply CSS using the custom attribute: [data-my-custom-label]::before { content: attr(data-my-custom-label); }

Additional Notes

The preparePlaceholderAttribute() function ensures that user-provided attribute names are automatically sanitized to produce valid HTML data attributes, preventing runtime errors or unexpected behavior.

Checklist

  • I have created a changeset for this PR if necessary.
  • My changes do not break the library.
  • I have added tests where applicable.
  • I have followed the project guidelines.
  • I have fixed any lint issues.

Related Issues

No related issues.

Copilot AI review requested due to automatic review settings January 28, 2026 11:08
@changeset-bot
Copy link

changeset-bot bot commented Jan 28, 2026

🦋 Changeset detected

Latest commit: f846d96

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 72 packages
Name Type
@tiptap/extensions Patch
@tiptap/starter-kit Patch
@tiptap/extension-character-count Patch
@tiptap/extension-dropcursor Patch
@tiptap/extension-focus Patch
@tiptap/extension-gapcursor Patch
@tiptap/extension-history Patch
@tiptap/extension-placeholder Patch
@tiptap/core Patch
@tiptap/extension-audio Patch
@tiptap/extension-blockquote Patch
@tiptap/extension-bold Patch
@tiptap/extension-bubble-menu Patch
@tiptap/extension-bullet-list Patch
@tiptap/extension-code-block-lowlight Patch
@tiptap/extension-code-block Patch
@tiptap/extension-code Patch
@tiptap/extension-collaboration-caret Patch
@tiptap/extension-collaboration Patch
@tiptap/extension-color Patch
@tiptap/extension-details Patch
@tiptap/extension-document Patch
@tiptap/extension-drag-handle-react Patch
@tiptap/extension-drag-handle-vue-2 Patch
@tiptap/extension-drag-handle-vue-3 Patch
@tiptap/extension-drag-handle Patch
@tiptap/extension-emoji Patch
@tiptap/extension-file-handler Patch
@tiptap/extension-floating-menu Patch
@tiptap/extension-font-family Patch
@tiptap/extension-hard-break Patch
@tiptap/extension-heading Patch
@tiptap/extension-highlight Patch
@tiptap/extension-horizontal-rule Patch
@tiptap/extension-image Patch
@tiptap/extension-invisible-characters Patch
@tiptap/extension-italic Patch
@tiptap/extension-link Patch
@tiptap/extension-list Patch
@tiptap/extension-mathematics Patch
@tiptap/extension-mention Patch
@tiptap/extension-node-range Patch
@tiptap/extension-ordered-list Patch
@tiptap/extension-paragraph Patch
@tiptap/extension-strike Patch
@tiptap/extension-subscript Patch
@tiptap/extension-superscript Patch
@tiptap/extension-table-of-contents Patch
@tiptap/extension-table Patch
@tiptap/extension-text-align Patch
@tiptap/extension-text-style Patch
@tiptap/extension-text Patch
@tiptap/extension-twitch Patch
@tiptap/extension-typography Patch
@tiptap/extension-underline Patch
@tiptap/extension-unique-id Patch
@tiptap/extension-youtube Patch
@tiptap/html Patch
@tiptap/markdown Patch
@tiptap/pm Patch
@tiptap/react Patch
@tiptap/static-renderer Patch
@tiptap/suggestion Patch
@tiptap/vue-2 Patch
@tiptap/vue-3 Patch
@tiptap/extension-list-item Patch
@tiptap/extension-list-keymap Patch
@tiptap/extension-table-cell Patch
@tiptap/extension-table-header Patch
@tiptap/extension-table-row Patch
@tiptap/extension-task-item Patch
@tiptap/extension-task-list Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@netlify
Copy link

netlify bot commented Jan 28, 2026

Deploy Preview for tiptap-embed ready!

Name Link
🔨 Latest commit f846d96
🔍 Latest deploy log https://app.netlify.com/projects/tiptap-embed/deploys/6979f76f0b8d390008e733d5
😎 Deploy Preview https://deploy-preview-7468--tiptap-embed.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Contributor

@arnaugomez arnaugomez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM but I wonder if, in the future, other devs will ask for more customization (like adding more attributes) and if a more generic solution could be achieved.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a configurable dataAttribute option to the Placeholder extension so consumers can choose which data-* attribute name is used for placeholder labels (useful for custom CSS selectors).

Changes:

  • Added dataAttribute to PlaceholderOptions (default: placeholder) and wired it into the decoration attributes.
  • Introduced preparePlaceholderAttribute() to normalize/sanitize the configured attribute name.
  • Added unit tests and a changeset entry for the new option.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

File Description
packages/extensions/src/placeholder/placeholder.ts Adds the new option + attribute-name preparation and uses it when creating placeholder decorations.
packages/extensions/src/placeholder/placeholder.spec.ts Adds unit tests validating default/custom attribute behavior and sanitization.
.changeset/placeholder-data-attribute.md Declares a patch release for @tiptap/extensions documenting the new option.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 28, 2026

Open in StackBlitz

@tiptap/core

npm i https://pkg.pr.new/@tiptap/core@7468

@tiptap/extension-blockquote

npm i https://pkg.pr.new/@tiptap/extension-blockquote@7468

@tiptap/extension-audio

npm i https://pkg.pr.new/@tiptap/extension-audio@7468

@tiptap/extension-bold

npm i https://pkg.pr.new/@tiptap/extension-bold@7468

@tiptap/extension-bubble-menu

npm i https://pkg.pr.new/@tiptap/extension-bubble-menu@7468

@tiptap/extension-bullet-list

npm i https://pkg.pr.new/@tiptap/extension-bullet-list@7468

@tiptap/extension-code

npm i https://pkg.pr.new/@tiptap/extension-code@7468

@tiptap/extension-code-block

npm i https://pkg.pr.new/@tiptap/extension-code-block@7468

@tiptap/extension-code-block-lowlight

npm i https://pkg.pr.new/@tiptap/extension-code-block-lowlight@7468

@tiptap/extension-collaboration

npm i https://pkg.pr.new/@tiptap/extension-collaboration@7468

@tiptap/extension-collaboration-caret

npm i https://pkg.pr.new/@tiptap/extension-collaboration-caret@7468

@tiptap/extension-details

npm i https://pkg.pr.new/@tiptap/extension-details@7468

@tiptap/extension-color

npm i https://pkg.pr.new/@tiptap/extension-color@7468

@tiptap/extension-document

npm i https://pkg.pr.new/@tiptap/extension-document@7468

@tiptap/extension-drag-handle

npm i https://pkg.pr.new/@tiptap/extension-drag-handle@7468

@tiptap/extension-drag-handle-react

npm i https://pkg.pr.new/@tiptap/extension-drag-handle-react@7468

@tiptap/extension-drag-handle-vue-2

npm i https://pkg.pr.new/@tiptap/extension-drag-handle-vue-2@7468

@tiptap/extension-drag-handle-vue-3

npm i https://pkg.pr.new/@tiptap/extension-drag-handle-vue-3@7468

@tiptap/extension-file-handler

npm i https://pkg.pr.new/@tiptap/extension-file-handler@7468

@tiptap/extension-emoji

npm i https://pkg.pr.new/@tiptap/extension-emoji@7468

@tiptap/extension-floating-menu

npm i https://pkg.pr.new/@tiptap/extension-floating-menu@7468

@tiptap/extension-font-family

npm i https://pkg.pr.new/@tiptap/extension-font-family@7468

@tiptap/extension-hard-break

npm i https://pkg.pr.new/@tiptap/extension-hard-break@7468

@tiptap/extension-heading

npm i https://pkg.pr.new/@tiptap/extension-heading@7468

@tiptap/extension-highlight

npm i https://pkg.pr.new/@tiptap/extension-highlight@7468

@tiptap/extension-horizontal-rule

npm i https://pkg.pr.new/@tiptap/extension-horizontal-rule@7468

@tiptap/extension-image

npm i https://pkg.pr.new/@tiptap/extension-image@7468

@tiptap/extension-invisible-characters

npm i https://pkg.pr.new/@tiptap/extension-invisible-characters@7468

@tiptap/extension-italic

npm i https://pkg.pr.new/@tiptap/extension-italic@7468

@tiptap/extension-link

npm i https://pkg.pr.new/@tiptap/extension-link@7468

@tiptap/extension-list

npm i https://pkg.pr.new/@tiptap/extension-list@7468

@tiptap/extension-mathematics

npm i https://pkg.pr.new/@tiptap/extension-mathematics@7468

@tiptap/extension-mention

npm i https://pkg.pr.new/@tiptap/extension-mention@7468

@tiptap/extension-node-range

npm i https://pkg.pr.new/@tiptap/extension-node-range@7468

@tiptap/extension-ordered-list

npm i https://pkg.pr.new/@tiptap/extension-ordered-list@7468

@tiptap/extension-paragraph

npm i https://pkg.pr.new/@tiptap/extension-paragraph@7468

@tiptap/extension-strike

npm i https://pkg.pr.new/@tiptap/extension-strike@7468

@tiptap/extension-subscript

npm i https://pkg.pr.new/@tiptap/extension-subscript@7468

@tiptap/extension-superscript

npm i https://pkg.pr.new/@tiptap/extension-superscript@7468

@tiptap/extension-table

npm i https://pkg.pr.new/@tiptap/extension-table@7468

@tiptap/extension-table-of-contents

npm i https://pkg.pr.new/@tiptap/extension-table-of-contents@7468

@tiptap/extension-text

npm i https://pkg.pr.new/@tiptap/extension-text@7468

@tiptap/extension-text-align

npm i https://pkg.pr.new/@tiptap/extension-text-align@7468

@tiptap/extension-text-style

npm i https://pkg.pr.new/@tiptap/extension-text-style@7468

@tiptap/extension-twitch

npm i https://pkg.pr.new/@tiptap/extension-twitch@7468

@tiptap/extension-typography

npm i https://pkg.pr.new/@tiptap/extension-typography@7468

@tiptap/extension-underline

npm i https://pkg.pr.new/@tiptap/extension-underline@7468

@tiptap/extension-unique-id

npm i https://pkg.pr.new/@tiptap/extension-unique-id@7468

@tiptap/extensions

npm i https://pkg.pr.new/@tiptap/extensions@7468

@tiptap/extension-youtube

npm i https://pkg.pr.new/@tiptap/extension-youtube@7468

@tiptap/html

npm i https://pkg.pr.new/@tiptap/html@7468

@tiptap/markdown

npm i https://pkg.pr.new/@tiptap/markdown@7468

@tiptap/react

npm i https://pkg.pr.new/@tiptap/react@7468

@tiptap/starter-kit

npm i https://pkg.pr.new/@tiptap/starter-kit@7468

@tiptap/pm

npm i https://pkg.pr.new/@tiptap/pm@7468

@tiptap/static-renderer

npm i https://pkg.pr.new/@tiptap/static-renderer@7468

@tiptap/suggestion

npm i https://pkg.pr.new/@tiptap/suggestion@7468

@tiptap/vue-2

npm i https://pkg.pr.new/@tiptap/vue-2@7468

@tiptap/vue-3

npm i https://pkg.pr.new/@tiptap/vue-3@7468

@tiptap/extension-character-count

npm i https://pkg.pr.new/@tiptap/extension-character-count@7468

@tiptap/extension-focus

npm i https://pkg.pr.new/@tiptap/extension-focus@7468

@tiptap/extension-dropcursor

npm i https://pkg.pr.new/@tiptap/extension-dropcursor@7468

@tiptap/extension-gapcursor

npm i https://pkg.pr.new/@tiptap/extension-gapcursor@7468

@tiptap/extension-history

npm i https://pkg.pr.new/@tiptap/extension-history@7468

@tiptap/extension-list-item

npm i https://pkg.pr.new/@tiptap/extension-list-item@7468

@tiptap/extension-list-keymap

npm i https://pkg.pr.new/@tiptap/extension-list-keymap@7468

@tiptap/extension-placeholder

npm i https://pkg.pr.new/@tiptap/extension-placeholder@7468

@tiptap/extension-table-cell

npm i https://pkg.pr.new/@tiptap/extension-table-cell@7468

@tiptap/extension-table-header

npm i https://pkg.pr.new/@tiptap/extension-table-header@7468

@tiptap/extension-table-row

npm i https://pkg.pr.new/@tiptap/extension-table-row@7468

@tiptap/extension-task-item

npm i https://pkg.pr.new/@tiptap/extension-task-item@7468

@tiptap/extension-task-list

npm i https://pkg.pr.new/@tiptap/extension-task-list@7468

commit: f846d96

@bdbch
Copy link
Member Author

bdbch commented Jan 28, 2026

LGTM but I wonder if, in the future, other devs will ask for more customization (like adding more attributes) and if a more generic solution could be achieved.

What exactly would a generic approach look like here? Do you have anything in mind?

@bdbch bdbch merged commit a65e55d into develop Jan 28, 2026
17 checks passed
@bdbch bdbch deleted the feature/placeholder-data-attribute-customization branch January 28, 2026 12:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants