jackbsteinberg/std-toast

Should infinite durations toasts default to having a close button?

Opened this issue · 2 comments

Certainly a toast without an action and a timeout seems like it needs a close button.

This is an interesting issue. Let me sum up the status quo as of #18:

  • If you use showToast(), the closeButton option defaults to true if duration ends up as Infinity. (Either because you set type: "warning"/type: "error", or because you explicitly set duration: Infinity.) You can still create an infinite-duration no-closebutton toast manually with showToast({ duration: Infinity, closeButton: false }).
  • If you use <std-toast>.show(), the default duration is based on the type="" attribute value, but the close button is controlled by the closebutton="" attribute value. (It is not impacted by the duration, either the default inferred from type="" or explicitly passed to show().) This means it is relatively easy to create an infinite-duration no-close-button toast, just by forgetting to set the closebutton="" attribute. In particular the following are situations that might not work as desired:
    • <std-toast type="error">.show(): default duration for warnings is infinite; no close button shown
    • <std-toast>.show({ duration: Infinity }): explicitly set infinite in JS, but never set closebutton="" in your HTML.

I see a few options here:

  1. Make show() automatically set the closebutton="" attribute if the duration is Infinity, similar to showToast.

    • This is somewhat strange, in that we usually leave content attributes to authors, and don't change them as a "side effect" of something else.
    • But maybe it is OK; after all, the whole point of .show() is to change the open="" attribute, so maybe changing the closebutton="" attribute as well is not a big step from there.
  2. No longer control the close button via an attribute. Instead, it is only present via a .show()/showToast() option.

    • I am a bit reluctant about this because "has a close button" doesn't seem very tied to showing, and saying that the only way you can control that is via show(), makes it a bit magic.
    • In particular, previously show() could be fully emulated by user code, but now it is toggling internal state in a way that cannot be replicated easily, which could be annoying if people want to do custom show code (with, I dunno, animations or something).
  3. CSS-centric:

    • Remove the closebutton="" attribute. To show the close button, you would use std-toast::part(closebutton) { display: block; }. (It defaults to display: none.)
    • Add a :state(infinite-duration) pseudo-class. This indicates matches when the element is being displayed for an infinite duration. Then the default stylesheet contains std-toast:state(infinite-duration)::part(closebutton) { display: block }.
    • Now all changes to the default are done via CSS, such as std-toast::part(closebutton) { display: ...; }.

(1) and (2) are both fairly easy. I think I am a bit more comfortable with (1) than (2).

(3) is interesting because it really leans on the idea of controlling the closebutton being a stylistic aspect of the element. Kind of like using CSS to control the "x" on <input type="search"> or the dropdown arrow on <select> or the marker for <details>. For example, design systems which say that all toasts must have a close button, would just have their own CSS rule for all toasts they produce, instead of requiring the HTML or JS to be changed for each toast.

I like (1) most as a strategy, but I agree that it seems strange to change the closeButton on a toast as a side effect of changing the duration. In addition, show() to me changes aspects of the toast with relation to their individual showings, whereas closeButton is more of a component of the toast itself.

As an alternative to avoid this weirdness, we could do nothing - make a recommendation that infinite-duration toasts should have a closeButton and leave it to developers to make that decision. There is something to be said about adding it automatically with type='warning|error' if those default to Infinity duration, but if a developer is manually adding duration: Infinity to their toasts I don't know that the toast should fill in a closeButton.