Skip to content

A custom toast render silently removes the toast's dismiss control, and Toaster exposes no pt #156

Description

@woksin

What happens

Toaster's ToastList composes each toast as icon + content + Toast.Close
(dist/esm/Notifications/Toaster.js):

<Toast.Root toast={item} data-severity={item.severity} className="cratis-toast">
    <Toast.Icon match="success"></Toast.Icon><Toast.Content><Toast.Title /><Toast.Description /></Toast.Content>
    <Toast.Close aria-label={dismissAriaLabel}><i className="pi pi-times" /></Toast.Close>
</Toast.Root>

PrimeReact's Toast.Root renders toast.render ?? props.children (primereact/toast, ToastRoot.render:
children: u?.render ?? t.children). So supplying render to the imperative toast(...) API — which this
package re-exports verbatim from primereact/toaster (dist/esm/Notifications/toast.d.ts) — replaces the
entire frame above, including Toast.Close.

A consumer who wants custom content loses the dismiss affordance and gets no warning; the only way out of the
toast becomes waiting for the timeout.

Separately, ToasterProps is { position, limit, timeout, dismissAriaLabel } — there is no pt, so the
region and each toast's chrome are unreachable from application code.

Evidence

@cratis/components 3.4.0, primereact 11.1.0.

We hit exactly this: our error toasts had a close button on PrimeReact 10 (closable: true) and lost it on the
first cut of the migration, with nothing in build, lint or specs reporting the loss.

Our workaround is to mint the toast id up front and render our own close button inside the custom body:

toast.error({ id, render: <Body onDismiss={() => toast.dismiss(id)} /> });

The substitution itself happens in PrimeReact's Toast.Root, not in this package's code — but toast is the
API this package exports and Toaster is the frame that is silently discarded, so the seam is here.

What it costs a consumer

One consumer-owned close button, plus the discovery cost of noticing the button is gone. Low, and we absorbed
it — but it is a sharp edge with no signal: the documented way to customize toast content silently removes an
accessibility affordance.

Suggested fix — the seam

Either:

  • compose render inside the toast frame, so custom content keeps the icon and the close control; or
  • document the trade explicitly at the toast(...) surface, and expose pt on Toaster so a consumer can
    reach the region and toast chrome without replacing the body.

What is explicitly not being asked for

Not asking for render to be removed or restricted, and not asking for a Components-owned toast design. Not
asking PrimeReact to change Toast.Root if Components would rather solve it at its own layer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions