← All proposals

Section Message

A copy of the PDS v2 Section Message (pds-section-message, same class names, props and behavior) with an agentic type (AI gradient border on a surface fill, the Agent Avatar as its leading icon (decided 2026-10-21; iconName picks its icon), the standard secondary Button as the CTA, a silver-muted Badge) and an avatarProps option for the avatar (halo, shape, size).

Extends a PDS componentOpen in Storybook

proposals/SectionMessage/section-message.css260 lines · View on GitHub
.pds-section-message {
	--message-bg: var(--pds-color-status-info-background);
	--message-fg: var(--pds-color-status-info-foreground);
	--message-border: var(--pds-color-status-info-border);

	background-color: var(--message-bg);
	border: var(--pds-border-width-default) solid var(--message-border);
	border-radius: var(--pds-border-radius-container);
	color: var(--pds-color-foreground-default);
	display: flex;
	flex-direction: column;
	padding: var(--pds-spacing-s) var(--pds-spacing-l) var(--pds-spacing-s)
		var(--pds-spacing-m);
	position: relative;

	@media (min-width: 768px) {
		align-items: center;
		flex-direction: row;
		gap: var(--pds-spacing-xl);
		justify-content: space-between;
	}

	/* The CTA takes the message's colors, except in a `discovery` or an
	   `agentic` message, where it is the standard PDS secondary Button. */
	&:not(.pds-section-message--discovery):not(.pds-section-message--agentic)
		.pds-button.pds-button--secondary {
		--button-background-color: var(--message-bg);
		--button-foreground-color: var(--message-fg);
		--button-foreground-color-hover: var(--message-fg);
		--button-border-color: var(--message-fg);

		&:hover:enabled {
			--button-background-color: color-mix(
				in oklch,
				var(--message-bg) 90%,
				var(--message-fg)
			);
		}
	}

	/* The link variant sets `color` directly rather than going through
	   --button-foreground-color, so match the message's own foreground here. */
	.pds-button.pds-button--link {
		color: var(--message-fg);

		&:hover:enabled,
		&:active:enabled {
			color: var(--message-fg);
		}
	}
}

.pds-section-message__content {
	align-items: flex-start;
	display: flex;
	gap: var(--pds-spacing-s);
}

.pds-section-message__header {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: var(--pds-spacing-xs);
	margin-block-end: var(--pds-spacing-2xs);
	margin-block-start: 0.125rem;
	min-height: var(--pds-spacing-xl);
}

.pds-section-message__title {
	color: var(--message-fg);
	font-size: var(--pds-typography-size-m);
	font-weight: var(--pds-typography-fw-semibold);
}

.pds-section-message__message {
	padding-inline-end: var(--pds-spacing-3xs);

	p {
		color: var(--pds-color-foreground-default);

		&:first-child {
			margin-block-start: 0;
		}

		&:last-child {
			margin-block-end: 0;
		}

		a {
			color: var(--pds-color-foreground-default);
		}
	}
}

.pds-section-message__icon {
	align-items: center;
	display: flex;
}

.pds-section-message__icon {
	color: var(--message-fg);
	/* One message line tall (size-s at 150% line-height) so the icon centers on
	   the first line of text when there's no title. */
	height: calc(var(--pds-typography-size-s) * 1.5);
}

.pds-section-message__actions {
	display: flex;
	gap: var(--pds-spacing-m);

	@media (max-width: 767px) {
		flex-wrap: wrap;
	}

	@media (min-width: 768px) {
		align-self: center;
	}
}

/* CTA button -- full width at sm */
.pds-section-message__cta {
	@media (max-width: 767px) {
		width: 100%;

		/* Only offset from the message text when nothing precedes it -- with a
		   secondary action the offset belongs to that instead. */
		&:first-child {
			margin-block-start: var(--pds-spacing-xl);
		}
	}
}

/* Secondary action -- stacks above the CTA at sm rather than sitting beside it */
.pds-section-message__secondary {
	@media (max-width: 767px) {
		justify-content: center;
		margin-block-start: var(--pds-spacing-xl);
		width: 100%;
	}
}

.pds-section-message__dismiss {
	align-self: center;
	background-color: var(--message-bg);
	color: var(--message-fg);
	flex-shrink: 0;

	&:hover {
		background-color: color-mix(
			in oklch,
			var(--message-bg) 90%,
			var(--message-fg)
		);
	}

	@media (max-width: 767px) {
		position: absolute;
		right: var(--pds-spacing-m);
		top: var(--pds-spacing-m);
	}
}

.pds-section-message--dismissing {
	animation: hideMessageAnimation ease-in 200ms;
	animation-fill-mode: forwards;
}

.pds-section-message--dismissed {
	display: none;
}

/* Has a title at md breakpoint and above */
@media (min-width: 768px) {
	.pds-section-message--hasTitle {
		align-items: flex-start;
		.pds-section-message__content {
			align-items: flex-start;
		}
	}
}

.pds-section-message__badge {
	transform: translateY(-0.0625rem);
}

/* With a title, the icon centers in the same fixed-height first row as the
   title and badge, so adding a badge doesn't shift anything. */
.pds-section-message--hasTitle .pds-section-message__icon {
	height: var(--pds-spacing-xl);
	margin-block-start: 0.125rem;
}

/* Has dismiss button at sm breakpoint */
@media (max-width: 767px) {
	.pds-section-message--hasDismiss {
		.pds-section-message__header,
		.pds-section-message__message {
			width: calc(100% - var(--pds-spacing-l));
		}
	}
}

/* Message type colors */
.pds-section-message--info {
	--message-bg: var(--pds-color-status-info-background);
	--message-border: var(--pds-color-status-info-border);
	--message-fg: var(--pds-color-status-info-foreground);
}
.pds-section-message--success {
	--message-bg: var(--pds-color-status-success-background);
	--message-border: var(--pds-color-status-success-border);
	--message-fg: var(--pds-color-status-success-foreground);
}
.pds-section-message--warning {
	--message-bg: var(--pds-color-status-warning-background);
	--message-border: var(--pds-color-status-warning-border);
	--message-fg: var(--pds-color-status-warning-foreground);
}
.pds-section-message--critical {
	--message-bg: var(--pds-color-status-critical-background);
	--message-border: var(--pds-color-status-critical-border);
	--message-fg: var(--pds-color-status-critical-foreground);
}
.pds-section-message--discovery {
	--message-bg: var(--pds-color-status-discovery-background);
	--message-border: var(--pds-color-status-discovery-border);
	--message-fg: var(--pds-color-status-discovery-foreground);
}

/* Agentic: the AI gradient as the border on a surface fill, as on the agentic
   Button. A gradient cannot go in border-color, so the border is transparent,
   the gradient is painted on the border-box and the surface layer covers the
   padding-box. Text and icon stay in the default foreground. */
.pds-section-message--agentic {
	--message-bg: var(--pds-color-surface-default);
	--message-fg: var(--pds-color-foreground-default);
}

/* The gradient border: the border is transparent and the gradient is painted
   on the border-box, with the fill layer on the padding-box above it. */
.pds-section-message--agentic {
	--message-border: transparent;

	background-clip: padding-box, border-box;
	background-color: transparent;
	background-image:
		linear-gradient(var(--message-bg), var(--message-bg)),
		var(--pds-gradient-ai-active);
	background-origin: border-box;
}

@keyframes hideMessageAnimation {
	to {
		opacity: 0;
	}
	from {
		opacity: 1;
	}
}