fix(widget): fill the inline container and keep typing keys in the widget (#15211)

This commit is contained in:
Yuhong Sun authored and GitHub committed 2026-09-29 01:02:06 +00:00
1 parent 0b8dbbb911
commit a18fc1a652
5 files changed
+41 -3

No files matched your search

+16 -1
View File
@@ -123,6 +123,7 @@ That's it! The widget will appear as a floating button in the bottom-right corne
| `text-color` | string | `#000000bf` | Text color (75% opacity black) |
| `mode` | string | `"launcher"` | Display mode: `"launcher"` or `"inline"` |
| `include-citations`| boolean | `false` | Include citation markers in responses |
| `start-expanded` | boolean | `false` | Inline mode: show the full chat panel before the first message, instead of the compact input bar |
**Note**: These attributes must be provided as HTML attributes. Only `backend-url` and `api-key` can optionally be set via environment variables for self-hosted builds.
@@ -232,7 +233,21 @@ The widget is embedded directly in your page layout. Perfect for dedicated suppo
</div>
```
**CSS Tip**: The widget will fill its container's dimensions in inline mode.
**CSS Tip**: The widget will fill its container's dimensions in inline mode. Give the container an explicit height; otherwise the panel grows with the conversation.
Before the first message, inline mode shows a compact input bar. Add `start-expanded` to show the full chat panel at the container's size from the start:
```html
<div style="height: 600px;">
<onyx-chat-widget mode="inline" start-expanded></onyx-chat-widget>
</div>
```
## Keyboard Events
Key presses typed into the widget do not propagate to the host page (except Escape). The widget uses Shadow DOM, so a page-level handler sees `event.target` as `<onyx-chat-widget>`, not the text field. Without this, handlers that block Backspace outside text fields would also block it in the widget.
Handlers registered in the capture phase still run first. If such a handler blocks keys outside text fields, check `event.composedPath()[0]` instead of `event.target`.
## Development
+1
View File
@@ -23,6 +23,7 @@ export function resolveConfig(attributes: Partial<WidgetConfig>): WidgetConfig {
logo: attributes.logo,
mode: attributes.mode || "launcher",
includeCitations: attributes.includeCitations ?? false,
startExpanded: attributes.startExpanded ?? false,
};
if (!config.backendUrl) {
+6
View File
@@ -10,6 +10,12 @@ export const widgetStyles = css`
font-family: var(--onyx-font-family);
}
/* Without a host height, the inline container's height: 100% resolves to
auto and the panel grows with its content instead of filling the parent. */
:host([mode="inline"]) {
height: 100%;
}
.launcher {
position: fixed;
background: var(--background-neutral-00);
+2
View File
@@ -29,6 +29,8 @@ export interface WidgetConfig {
// Optional - Display
mode?: "launcher" | "inline";
// Inline mode: show the full chat panel before the first message.
startExpanded?: boolean;
// Optional - Citations
includeCitations?: boolean;
+16 -2
View File
@@ -35,9 +35,12 @@ export class OnyxChatWidget extends LitElement {
@property({ attribute: "text-color" }) textColor?: string;
@property({ attribute: "agent-name" }) agentName?: string;
@property({ attribute: "logo" }) logo?: string;
@property() mode?: "launcher" | "inline";
// Reflected so `:host([mode="inline"])` also matches when set as a property.
@property({ reflect: true }) mode?: "launcher" | "inline";
@property({ attribute: "include-citations", type: Boolean })
includeCitations?: boolean;
@property({ attribute: "start-expanded", type: Boolean })
startExpanded?: boolean;
// Assigned as a JS property, since a function cannot ride an HTML attribute.
// Takes precedence over `api-key` and keeps the credential out of the markup.
@@ -113,6 +116,7 @@ export class OnyxChatWidget extends LitElement {
logo: this.logo,
mode: this.mode,
includeCitations: this.includeCitations,
startExpanded: this.startExpanded,
});
// Apply custom colors
@@ -358,6 +362,13 @@ export class OnyxChatWidget extends LitElement {
}
private handleKeyDown(e: KeyboardEvent) {
// Shadow DOM retargets `e.target` to the host element, so page-level
// handlers that let keys through only for text fields (e.g. ones that
// block Backspace navigation) would cancel typing here. Escape still
// propagates so the host page can close its overlays.
if (e.key !== "Escape") {
e.stopPropagation();
}
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
this.sendMessage();
@@ -538,7 +549,10 @@ export class OnyxChatWidget extends LitElement {
render() {
const showContainer = this.config.mode === "inline" || this.isOpen;
const hasMessages = this.messages.length > 0 || this.isStreaming;
const isCompactInline = this.config.mode === "inline" && !hasMessages;
const isCompactInline =
this.config.mode === "inline" &&
!this.config.startExpanded &&
!hasMessages;
return html`
${this.config.mode === "launcher"