← All proposals

Chat Input

A labelled textarea with a toolbar inside the same bordered box:

Net-new componentOpen in Storybook

proposals/ChatInput/chat-input.css131 lines · View on GitHub
/* The border, background and focus ring live on the field, not the textarea,
   so the toolbar sits inside the same box. Resizing also targets the field,
   which puts the drag handle in the bottom corner, below the toolbar. */
.pds-chat-input {
	--chat-input-padding: var(--pds-spacing-xs);
}

.pds-chat-input--m {
	--chat-input-padding: var(--pds-spacing-s);
}

.pds-chat-input__above-field {
	background-color: var(--pds-color-surface-default-secondary);
	border: var(--pds-border-width-default) solid
		var(--pds-color-border-default-secondary);
	border-bottom: 0;
	border-radius: var(--pds-border-radius-input) var(--pds-border-radius-input) 0
		0;
	margin-inline: var(--pds-spacing-xs);
	padding: var(--pds-spacing-2xs) var(--pds-spacing-s);
}

.pds-chat-input__field-header {
	align-items: center;
	display: flex;
	flex-shrink: 0;
	flex-wrap: wrap;
	gap: var(--pds-spacing-2xs);
	padding: var(--chat-input-padding) var(--chat-input-padding) 0;
}

.pds-chat-input__field {
	background-color: var(--pds-color-surface-default);
	border: var(--pds-border-width-default) solid var(--pds-color-border-input);
	border-radius: var(--pds-border-radius-input);
	display: flex;
	flex-direction: column;
	overflow: hidden;

	&:focus-within {
		outline: var(--pds-border-width-outline) solid
			var(--pds-color-interactive-focus);
		outline-offset: 0;
	}
}

/* Files dragged over the field: a dashed focus-colored border and a focus-blue
   tint (the info background), not the neutral hover grey. The optional label sits over the field, so the pointer events
   pass through it and the drag counter stays accurate. */
.pds-chat-input__field {
	position: relative;
}

.pds-chat-input__field.pds-is-drag-over {
	background-color: var(--pds-color-status-info-background);
	border-color: var(--pds-color-interactive-focus);
	border-style: dashed;
}

.pds-chat-input__drop-label {
	align-items: center;
	background-color: var(--pds-color-status-info-background);
	color: var(--pds-color-status-info-foreground);
	display: flex;
	font-size: var(--pds-typography-size-s);
	inset: 0;
	justify-content: center;
	pointer-events: none;
	position: absolute;
	z-index: 1;
}

.pds-chat-input__field.pds-is-resizable {
	resize: vertical;
}

.pds-chat-input__textarea {
	background-color: transparent;
	border: 0;
	color: var(--pds-color-foreground-default);
	flex-grow: 1;
	font-family: var(--pds-typography-ff-default);
	font-size: var(--pds-typography-size-s);
	line-height: var(--pds-typography-lh-l);
	min-height: 0;
	outline: none;
	padding: var(--chat-input-padding);
	resize: none;

	&::placeholder {
		color: var(--pds-color-input-placeholder);
	}
}

.pds-chat-input__actions {
	align-items: center;
	display: flex;
	flex-shrink: 0;
	gap: var(--pds-spacing-s);
	justify-content: space-between;
	padding: var(--pds-spacing-2xs) var(--pds-spacing-xs) var(--pds-spacing-xs);
}

.pds-chat-input__actions-start,
.pds-chat-input__actions-end {
	align-items: center;
	display: flex;
	gap: var(--pds-spacing-2xs);
}

/* Compact: one row. The controls sit beside the text instead of under it, and
   the field header (if any) sits above the row.
   Keeps the standard input radius, like every other PDS field. */
.pds-chat-input--compact .pds-chat-input__field {
	resize: none;
}

.pds-chat-input__row {
	align-items: center;
	display: flex;
	gap: var(--pds-spacing-xs);
	padding: var(--pds-spacing-xs);
}

.pds-chat-input--compact .pds-chat-input__textarea {
	flex: 1 1 0;
	min-width: 0;
	overflow: hidden;
	padding: 0 var(--pds-spacing-2xs);
}