Skip to content

Conversation

@Jermolene
Copy link
Member

@Jermolene Jermolene commented Jan 23, 2026

This is an experiment to explore ways of ameliorating TiddlyWiki's habit of inserting extraneous <p> tags.

Motivation

The HTML specification says that <p> tags cannot contain other <p> tags. TiddlyWiki cheerfully violates this rule (and a bunch of other HTML strictures). In practice, browsers are mostly tolerant of the mis-nesting, but it can cause problems when TiddlyWiki output is consumed by other systems. Also, making the result look correct frequently requires the sort of CSS contortions that are not fun.

Mechanism

These changes allow automatically generated <p> tags to be replaced with any other tag (eg <div>), with the option of adding a class to the element at the same time.

It is similar to the existing mechanism for overriding widgets, but just involves overriding the tag generated by the element widget, and so the changes are entirely within that widget

The mappings are specified via specially named variables. The mapping only occurs within the scope of the variable. This example replaces <p> tags with <div> tags, adding the class my-class:

\define tv-map-p() div
\define tv-map-p-class() my-class

The end result is that it is possible to completely suppress paragraph generation within a portion of the widget tree.

Questions

This implementation does what it is intended to do, but at this point it is not clear that it represents a practical and broad solution, and so this PR is really just fuel for thought.

  • Would a better approach be to refactor the core templates to remove the troublesome tags? The usual objection is that this would have an impact on CSS selectors used by third party plugins, but perhaps we could handle that by shipping a plugin containing the existing templates for backwards compatibility purposes
  • Would it be useful to be able to completely remove the <p> tags, without replacing them with another tag?
  • Would it be useful to (somehow) have <p> tags automatically setting a mapping to prevent any descendent paragraph tags

@netlify
Copy link

netlify bot commented Jan 23, 2026

Deploy Preview for tiddlywiki-previews ready!

Name Link
🔨 Latest commit f29de0c
🔍 Latest deploy log https://app.netlify.com/projects/tiddlywiki-previews/deploys/6974017310d58d000744ae67
😎 Deploy Preview https://deploy-preview-9610--tiddlywiki-previews.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.

@github-actions
Copy link

Confirmed: Jermolene has already signed the Contributor License Agreement (see contributing.md)

@github-actions
Copy link

github-actions bot commented Jan 23, 2026

📊 Build Size Comparison: empty.html

Branch Size
Base (master) 2448.0 KB
PR 2448.9 KB

Diff: ⬆️ Increase: +1.0 KB


⚠️ Change Note Status

This PR appears to contain code changes but doesn't include a change note.

Please add a change note by creating a .tid file in editions/tw5.com/tiddlers/releasenotes/<version>/

📚 Documentation: Release Notes and Changes

💡 Note: If this is a documentation-only change, you can ignore this message.

@pmario
Copy link
Member

pmario commented Jan 24, 2026

I know it's an experiment. My concerns:

a) It seems to also replace valid P tags. IMO that makes it very hard for to use with user templates / forms that have text and widgets
b) IMO it's complicated to use if I want to remove P tags instead of replacing all of them
c) It does not solve the problem of redundant elements that interfere with CSS styling

I see it as a workaround, which will make styling even more complex.


From my point of view it is a parser problem and not a rendering problem. The redundant P tags should not be created.

IMO the problematic code is in WikiParser.prototype.parseBlock when it returns a hardcoded P tag, even if HTML block tags or widgets are defined, that emit a block DOM element.

In these cases it should not create a P tag at all. IMO the following assumptions: // Treat it as a paragraph if we didn't find a block rule is wrong

// Treat it as a paragraph if we didn't find a block rule
var start = this.pos;
var children = this.parseInlineRun(terminatorRegExp);
var end = this.pos;
return [{type: "element", tag: "p", children: children, start: start, end: end, rule: "parseblock" }];
};


As I did create my experiments, there where many places in the core UI, where redundant P tags caused problems.

Today, IMO there are only a view places left, which could create backwards compatibility problems. Mainly for 3rd party plugins.

Most of the redundant P tags have been fixed, without problems.

I will merge master into my experiments, so I can be more specific.

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.

3 participants