Skip to content

fix(ui): improve list rendering in event descriptions#29760

Open
akshitj11 wants to merge 4 commits into
calcom:mainfrom
akshitj11:fix/ui-event-description-lists-24366
Open

fix(ui): improve list rendering in event descriptions#29760
akshitj11 wants to merge 4 commits into
calcom:mainfrom
akshitj11:fix/ui-event-description-lists-24366

Conversation

@akshitj11

@akshitj11 akshitj11 commented Jul 13, 2026

Copy link
Copy Markdown

What does this PR do?

Event descriptions with a numbered list followed by trailing bullet points rendered incorrectly on the booking page — nested <ul> elements appeared as orphan list items and bullets were misaligned due to list-style-position: inside.

This PR improves markdown list rendering by using outside list markers, merging orphaned nested <ul> siblings into their parent <li>, and adding regression tests.

Visual Demo (For contributors especially)

A visual demonstration is strongly recommended, for both the original and new change (video / image - any one).

Video Demo (if applicable):

  • Record the booking page with an event description containing 1. step followed by - bullet one and - bullet two. Before: trailing bullets missing or misaligned. After: both bullets render with outside markers.

Image Demo (if applicable):

  • Side-by-side screenshot of booking page event description: before (broken trailing bullets) vs after (correct list formatting).

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • I have updated the developer docs if this PR makes changes that would require a documentation change. If N/A, write N/A here and check the checkbox. (N/A)
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

  • Are there environment variables that should be set?
    • None.
  • What are the minimal test data to have?
    • An event type description with a numbered list followed by two bullet points at the end, e.g.:
      1. First step
      2. Second step
      
      - Bullet one
      - Bullet two
      
  • What is expected (happy path) to have (input and output)?
    • Input: open the booking page for that event type.
    • Output: both trailing bullets visible, aligned with outside list markers; nested sub-bullets stay under their parent numbered item.
  • Any other important info that could help to test that PR
    • Run: yarn vitest run packages/lib/markdownToSafeHTML.test.ts (3 tests pass).

Use outside list markers, merge orphaned nested lists, and add regression
tests for numbered lists followed by trailing bullet points.

Fixes calcom#24366
@github-actions

Copy link
Copy Markdown
Contributor

Welcome to Cal.diy, @akshitj11! Thanks for opening this pull request.

A few things to keep in mind:

  • This is Cal.diy, not Cal.com. Cal.diy is a community-driven, fully open-source fork of Cal.com licensed under MIT. Your changes here will be part of Cal.diy — they will not be deployed to the Cal.com production app.
  • Please review our Contributing Guidelines if you haven't already.
  • Make sure your PR title follows the Conventional Commits format.

A maintainer will review your PR soon. Thanks for contributing!

@github-actions github-actions Bot added Low priority Created by Linear-GitHub Sync 🧹 Improvements Improvements to existing features. Mostly UX/UI labels Jul 13, 2026
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@akshitj11, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 16 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5a793218-6786-4c62-8eed-a4c9a54f54a3

📥 Commits

Reviewing files that changed from the base of the PR and between c1b54bb and d3690c5.

📒 Files selected for processing (1)
  • packages/lib/markdownToSafeHTML.test.ts
📝 Walkthrough

Walkthrough

Updated both markdown-to-safe-HTML implementations to repeatedly nest sibling unordered lists under the preceding list item and to use outside list positioning. Added Vitest coverage for ordered and unordered lists, nested bullets, mixed list and paragraph content, styling, and item ordering.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: improving event description list rendering.
Description check ✅ Passed The description is directly about fixing list rendering and adding regression tests for the same issue.
Linked Issues check ✅ Passed The changes address the reported trailing bullet formatting bug in event descriptions and add regression coverage.
Out of Scope Changes check ✅ Passed The modified code and tests stay within the markdown list rendering fix and do not introduce unrelated scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
packages/lib/markdownToSafeHTML.test.ts (1)

1-53: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding tests for markdownToSafeHTMLClient as well.

Both implementations share identical formatting logic, but only the server-side markdownToSafeHTML is tested. If the implementations diverge (e.g., one gets a fix the other doesn't), the lack of client-side tests could allow regressions to go unnoticed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/lib/markdownToSafeHTML.test.ts` around lines 1 - 53, Add equivalent
coverage for markdownToSafeHTMLClient alongside the existing markdownToSafeHTML
tests, covering ordered/unordered lists, nested trailing sub-bullets, and mixed
paragraphs with bullets. Reuse the same expected formatting and safety
assertions so client-side regressions are detected if the implementations
diverge.
packages/lib/markdownToSafeHTML.ts (1)

17-43: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract shared list formatting logic to avoid duplication with markdownToSafeHTMLClient.ts.

The nested list transformation loop and the entire styling .replace() chain (lines 17-43) are identical in both markdownToSafeHTML.ts and markdownToSafeHTMLClient.ts. Only the sanitization step differs (sanitizeHtml vs DOMPurify.sanitize). Extracting the post-sanitization formatting into a shared utility (e.g., formatListHTML(safeHTML: string): string) would prevent the two implementations from diverging.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/lib/markdownToSafeHTML.ts` around lines 17 - 43, The
post-sanitization formatting in markdownToSafeHTML and markdownToSafeHTMLClient
is duplicated. Extract the nested-list transformation loop and styling
replacement chain into a shared formatListHTML(safeHTML: string) utility, then
have both functions call it after their respective sanitization steps while
preserving the existing output.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/lib/markdownToSafeHTML.test.ts`:
- Line 34: Update the nested-list assertion in the markdown-to-safe-HTML test to
match li elements with attributes by using the broader li opening-tag pattern,
while preserving the existing whitespace and nested ul structure so the
assertion fails for untransformed output and passes only for the corrected text
placement.

In `@packages/lib/markdownToSafeHTML.ts`:
- Around line 17-29: Broaden nestedListInSiblingLiPattern in
markdownToSafeHTML.ts to match arbitrary safe inline content before the sibling
nested <ul>, preserving captured attributes and inner list content during
merging. Apply the same matcher change in markdownToSafeHTMLClient.ts, and add a
regression test covering inline content such as a link, emphasis, code, span, or
a mixed combination.

---

Nitpick comments:
In `@packages/lib/markdownToSafeHTML.test.ts`:
- Around line 1-53: Add equivalent coverage for markdownToSafeHTMLClient
alongside the existing markdownToSafeHTML tests, covering ordered/unordered
lists, nested trailing sub-bullets, and mixed paragraphs with bullets. Reuse the
same expected formatting and safety assertions so client-side regressions are
detected if the implementations diverge.

In `@packages/lib/markdownToSafeHTML.ts`:
- Around line 17-43: The post-sanitization formatting in markdownToSafeHTML and
markdownToSafeHTMLClient is duplicated. Extract the nested-list transformation
loop and styling replacement chain into a shared formatListHTML(safeHTML:
string) utility, then have both functions call it after their respective
sanitization steps while preserving the existing output.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 755289c0-1214-4533-a6bb-17dbfa851f05

📥 Commits

Reviewing files that changed from the base of the PR and between f004349 and 09529fe.

📒 Files selected for processing (3)
  • packages/lib/markdownToSafeHTML.test.ts
  • packages/lib/markdownToSafeHTML.ts
  • packages/lib/markdownToSafeHTMLClient.ts

Comment thread packages/lib/markdownToSafeHTML.test.ts Outdated
Comment thread packages/lib/markdownToSafeHTML.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/lib/markdownToSafeHTML.ts (1)

18-28: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Avoid regex-based matching for nested <ul> structures.

([\s\S]*?)<\/ul> stops at the first closing </ul>. For lists nested more than one level, the replacement can consume the wrong closing </li> and emit malformed HTML. Add a multi-level regression test and use DOM/stack-based normalization instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/lib/markdownToSafeHTML.ts` around lines 18 - 28, The nested-list
normalization around nestedListInSiblingLiPattern must not use regex matching,
because it cannot correctly pair multi-level ul/li elements. Replace the regex
loop with DOM- or stack-based traversal that identifies a text-only li followed
by a sibling li containing its nested ul, moves that ul into the preceding li,
and preserves valid structure at every depth. Add a regression test covering
lists nested more than one level.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/lib/markdownToSafeHTML.ts`:
- Around line 18-28: The nested-list normalization around
nestedListInSiblingLiPattern must not use regex matching, because it cannot
correctly pair multi-level ul/li elements. Replace the regex loop with DOM- or
stack-based traversal that identifies a text-only li followed by a sibling li
containing its nested ul, moves that ul into the preceding li, and preserves
valid structure at every depth. Add a regression test covering lists nested more
than one level.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e5b45a38-4cd1-44b5-8cc5-2ca954527500

📥 Commits

Reviewing files that changed from the base of the PR and between 09529fe and 550c3b5.

📒 Files selected for processing (2)
  • packages/lib/markdownToSafeHTML.ts
  • packages/lib/markdownToSafeHTMLClient.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/lib/markdownToSafeHTMLClient.ts

Fix vacuous nested-list test assertion and broaden li content matching
for inline HTML in markdownToSafeHTML helpers.
@akshitj11

Copy link
Copy Markdown
Author

CodeRabbit fixes pushed. Please add the run-ci label. Thanks.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/lib/markdownToSafeHTML.test.ts (1)

15-20: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Bind assertions to the expected list structure.

The current matches can start at any <li> and cross </li> boundaries, so the tests may pass even if bullet text is rendered outside the <ul>. They also do not verify that the ordered list precedes the unordered list or that both list items have the expected styling.

🐛 Proposed fix
-    expect(html).toContain("<ol");
-    expect(html).toContain("<ul");
-    expect(html.match(/<li[^>]*>[\s\S]*?Bullet one/g)?.length).toBeGreaterThanOrEqual(1);
-    expect(html.match(/<li[^>]*>[\s\S]*?Bullet two/g)?.length).toBeGreaterThanOrEqual(1);
+    expect(html).toMatch(/<ol[^>]*>[\s\S]*?<\/ol>[\s\S]*?<ul[^>]*>/);
+    expect(html).toMatch(
+      /<ul[^>]*>[\s\S]*?<li[^>]*>\s*Bullet one[\s\S]*?<\/li>[\s\S]*?<li[^>]*>\s*Bullet two[\s\S]*?<\/li>[\s\S]*?<\/ul>/
+    );

-    expect(html).toContain("Item A");
-    expect(html).toContain("Item B");
-    expect(html).toContain("list-style-position: outside");
+    expect(html).toMatch(
+      /<ul[^>]*>[\s\S]*?<li[^>]*>\s*Item A[\s\S]*?<\/li>[\s\S]*?<li[^>]*>\s*Item B[\s\S]*?<\/li>[\s\S]*?<\/ul>/
+    );

Also applies to: 59-63

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/lib/markdownToSafeHTML.test.ts` around lines 15 - 20, Strengthen the
list assertions in the markdown-to-safe-HTML test by matching each expected item
within its correct list structure, preventing matches from crossing </li>
boundaries. Verify the ordered list appears before the unordered list, and
assert both list items include the expected styling; apply the same
structure-aware checks to the corresponding assertions around the second list.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/lib/markdownToSafeHTML.test.ts`:
- Around line 15-20: Strengthen the list assertions in the markdown-to-safe-HTML
test by matching each expected item within its correct list structure,
preventing matches from crossing </li> boundaries. Verify the ordered list
appears before the unordered list, and assert both list items include the
expected styling; apply the same structure-aware checks to the corresponding
assertions around the second list.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3efbf3eb-94c6-4a8f-a167-63c9598810cd

📥 Commits

Reviewing files that changed from the base of the PR and between 550c3b5 and c1b54bb.

📒 Files selected for processing (3)
  • packages/lib/markdownToSafeHTML.test.ts
  • packages/lib/markdownToSafeHTML.ts
  • packages/lib/markdownToSafeHTMLClient.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/lib/markdownToSafeHTMLClient.ts
  • packages/lib/markdownToSafeHTML.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🧹 Improvements Improvements to existing features. Mostly UX/UI Low priority Created by Linear-GitHub Sync size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

issue with bullet points in event type description

1 participant