shoelace-style / shoelace

A collection of professionally designed, every day UI components built on Web standards. SHOELACE IS BECOMING WEB AWESOME πŸ‘‡πŸ‘‡πŸ‘‡
https://webawesome.com
MIT License
12.93k stars 828 forks source link

Notification ("Toast") #111

Closed claviska closed 4 years ago

claviska commented 4 years ago

A toast/snackbar component (or utility) that shows an unobtrusive alert.

Please vote for this feature with πŸ‘ or πŸ‘Ž

ranjeetsinghbnl commented 4 years ago

@claviska I like how ui-library implement the toast ui-library-toast They use a different approach, like dynamically creating the components on run time. Similar way angular material does with cdk-overlay.

ui-libarary toast only show the message, for other features we can implement. I guess they are not be too complex.

its a good starting point.

claviska commented 4 years ago

The trouble with a controller is that you can't compose things neatly.

Alerts can contain arbitrary HTML, for example, so you'd have to expose some kind of html argument, not just a message string. But what if the alert has something like an "undo" button in it? How would you listen to it if the button were passed as an HTML string?

Or you could go down the road of accepting opinionated arguments such as message, iconName, iconURL, buttons[] β€” it quickly gets messy and ultimately limits what you can do. πŸ˜•

So I came up with this the other day. It involves extending the show method to support a "toast" interface. In this example, queueing would be handled by the component, not a utility.

<sl-alert>
  <sl-icon slot="icon" name="info-circle"></sl-icon>
  This is an alert!
</sl-alert>

<script>
const alert = document.querySelector('sl-alert');

alert.show({
  toast: true,
  position: 'top-start',
  duration: Infinity
});
</script>

This leaves composition up to the user so they can create the element in their HTML template or in JS with document.createElement(). They could also create a thin wrapper based on their needs with shortcut methods:

function customAlert(message, duration) {
  const alert = document.createElement('sl-alert');
  alert.textContent = message;
  alert.show({
    toast: true,
    duration
  });
}

Not sure. Still need to think about this some more.

ranjeetsinghbnl commented 4 years ago

yea it totally make sense, the way you ave mentioned. I like this idea. Even you can do a more research over it by checking the angular material snackebar

claviska commented 4 years ago

I experimented with this approach. Preview here: https://shoelace-97gynyc7a.vercel.app/components/alert?id=toast-notifications

My concerns:

I spent some time looking at other web components and how they're doing it. I haven't found a single example that supports multiple/stackable toast notifications in a declarative way.

I may experiment with an imperative approach, similar to what Lightning is doing. If there's an imperative API that covers 95% of use cases, maybe that's the better approach. Something like:

import { createNotification } from '@shoelace-style/shoelace';

createNotification({
  type: 'primary',
  closable: true,
  duration: 3000,
  title: 'Toast',
  message: 'This is a toast notification',
  iconName: 'info-circle',
  iconSrc: null, // for custom icons
});

Then we can expose an advanced property that lets you pass in an <sl-alert> element should you need to fully customize it:

import { createNotification } from '@shoelace-style/shoelace';

const alert = document.createElement('sl-alert');
alert.type = 'primary';
alert.innerHTML = '...';

createNotification({
  element: alert
});

Thoughts?

claviska commented 4 years ago

Another experiment: https://shoelace-7j37ar5bp.vercel.app/components/alert?id=toast-notifications

The docs and the source sums up this approach, but it basically exposes a toast() method that hoists and shows the notification.

This is my favorite approach thus far, but I’d still like some feedback on it.

claviska commented 4 years ago

Implemented in e797f2788252d341d81803921d6759116cc7f9dc.