fix(chat-widget): empty-state placeholder doesn't clear — :host([hidden]) override#1254
Merged
Conversation
…) override Joel reported: chat widget's "Send your first message / Try @Helper..." empty-state placeholder doesn't clear when the room actually has messages. Visible after sending "my first message" into a room that already had two prior messages — the empty-state panel still shows below them. ## Root cause `EmptyStateWidget` (LitElement, custom element `<empty-state>`) defines: :host { display: flex; ... } ChatWidget toggles the empty state via the HTML `hidden` attribute (updateEntityCount → emptyState.toggleAttribute('hidden', !isEmpty)). The `hidden` attribute applies `display: none` via the user-agent stylesheet — but the more-specific author rule `:host { display: flex }` WINS the cascade, so `hidden` has zero visual effect. The toggle silently no-ops; the panel keeps rendering. This is the well-known custom-element-with-explicit-display gotcha documented in the HTML5 spec: https://html.spec.whatwg.org/multipage/interaction.html#the-hidden-attribute ## Fix Add an explicit `:host([hidden]) { display: none; }` rule to the component's static styles. Wins by being more specific than `:host` alone (attribute selector wraps the host pseudo-class). Other consumers of `<empty-state>` (UserListWidget, RoomListWidget, TrainingDashboardWidget, the various Reactive* widgets) avoided this bug by accident — they use `${this.isEmpty ? this.renderEmptyState() : nothing}` to conditionally include the element rather than always-in- DOM + toggle-hidden. ChatWidget chose the toggle-hidden pattern deliberately because of CSS sibling rules around .messages-container, so the right fix is to make `hidden` work as expected for the component. ## Verification - `npm run build:ts` clean. - Comment in code documents the gotcha + spec link so future readers understand why the rule is load-bearing (4 lines of CSS that look redundant alongside `:host { display: flex }` until you know the cascade history). CSS-only behavioral fix: zero functional changes, no test added (UI visual verification is the appropriate sign-off; will follow up after merge with `npm start` + screenshot of a freshly-loaded populated room showing no empty-state placeholder).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug (Joel reported)
Chat widget's "💬 Send your first message / Try @Helper..." empty-state placeholder doesn't clear when the room actually has messages. Visible after sending a fresh message into a room with prior history — the empty-state panel still shows below the messages.
Root cause
EmptyStateWidget(LitElement custom element<empty-state>) defines:ChatWidget toggles the empty state via the HTML
hiddenattribute (updateEntityCount()→emptyState.toggleAttribute('hidden', !isEmpty)). Thehiddenattribute appliesdisplay: nonevia the user-agent stylesheet — but the more-specific author rule:host { display: flex }WINS the cascade, sohiddenhas zero visual effect. The toggle silently no-ops; the panel keeps rendering.This is the well-known custom-element-with-explicit-display gotcha called out in the HTML5 spec: https://html.spec.whatwg.org/multipage/interaction.html#the-hidden-attribute
Fix
Add an explicit
:host([hidden]) { display: none; }rule to the component's static styles.Wins by being more specific than
:hostalone (attribute selector wraps the host pseudo-class).Why other consumers weren't broken
UserListWidget, RoomListWidget, TrainingDashboardWidget, the Reactive* widgets all use
${this.isEmpty ? this.renderEmptyState() : nothing}— they conditionally include the element in the template rather than always-in-DOM + toggle-hidden. ChatWidget chose the toggle-hidden pattern because of the surrounding container/sibling layout, so the right fix is to makehiddenwork as expected for the component (benefits any future caller that uses the toggle pattern too).Verification
npm run build:tsclean.:host { display: flex }until you know the cascade history.UI visual verification: this is a CSS-only fix to a well-understood class of bug; will follow up after merge with
npm start+ screenshot of a freshly-loaded populated room showing no empty-state placeholder.