aws-amplify / aws-amplify/amplify-ui
Toast component
- Dominant language
- TypeScript
- Stars
- 1.1k
- Forks
- 347
- Avg merge
- 18h 29m
- Merged PRs (30d)
- 9
Description
### On which framework/platform would you like to see this feature implemented?
React
### Which UI component is this feature-request for?
Other
### Please describe your feature-request in detail.
I would like to propose a new Toast feature that would allow customers to display a notification (a.k.a. toast) on screen. This **would not be a connected component** and would be used for purely frontend-related notifications (i.e. An error occurred, message sent successfully).
With this component being provided by Amplify UI customers could avoid to have to implement their own component / system and thus reduce boilerplate code. This component would leverage the existing [Hub](https://docs.amplify.aws/lib/utilities/hub/q/platform/js/) utility to allow user to send toasts from any component in their app.
Having this component would allow customers to make their applications more engaging as displaying notifications that provide context to end users as result of an action is a common pattern in modern apps.
### Please describe a solution you'd like.
Below an high-level and non-exhaustive example of how the feature could be implemented in Amplify UI:
- Define a `Toast` component (you might already have this one for the Pinpoint-related features)
- Define a _container_ component that essentially sets a [Hub](https://docs.amplify.aws/lib/utilities/hub/q/platform/js/) listener on a specific channel (i.e. `notifications` or `toasts`) and renders a new `Toast` component (using a list/set given that there might be multiple toasts at any time on screen). This component is also in charge of removing a toast after it expires (as defined by the `duration` props).
```ts
import React, { useEffect, useState } from "react";
import { Hub } from "aws-amplify";
import type { HubCallback } from "@aws-amplify/core";
// Toast component (the actual notification/toast)
type ToastPlacement = "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-left"; // etc.
type ToastStatus = "success" | "error" | "warning" | "info";
type ToastProps = {
children?: React.ReactNode;
title?: string;
description: string;
duration?: number;
status: ToastStatus;
isClosable: boolean;
placement: ToastPlacement;
}
const Toast: React.FC = ({ title, description, duration, status, isClosable, placement }) => {
return (
// Markup for the single toast that takes in account the props passed + any default value (i.e. default duration 2500ms)
);
};
// Toast context (name TBD) - the container of the toasts that also listens for new toasts being sent
type ToastContextProps = {
children?: React.ReactNode;
};
const ToastContext: React.FC = ({ children }) => {
const [toastList, setToastList] = useState([]);
const handleNotifications: HubCallback = ({ payload: { data } }) => {
// Creates a timeout equal to the duration passed (or default duration). This timeout will be used to remove the toast when duration reaches 0
// Adds the toast to the list
setToastList([...toastList, {
title: data?.title || null,
description: data?.description || null,
status: data?.status || "success",
duration: data?.duration || 5000,
isClosable: data?.isCloseable || true,
placement: data?.placement ||
})];
};
useEffect(() => {
Hub.listen("notifications", handleNotifications);
// Clean up subscriptions when the component unmounts
return () => {
Hub.remove("notifications", handleNotifications);
};
});
return (
<>
{children}
// The toasts would be displayed vertically in descending order of arrival
{toastList.map((toast, idx) => }
)
}
```
Below instead an example of how customers could use the feature to send a notification, there are two pieces to it:
- Import the new `ToastContext` from Amplify UI, this component should be used high in the tree and wrap the app
- Leverage the existing `Hub` from `aws-amplify` to send a notification/create a toast
```ts
import React from "react";
import { Hub } from "aws-amplify";
import { ToastContext } from "@aws-amplify/ui";
type MyComponentProps = {
children?: React.ReactNode;
};
const MyComponent = () => {
const handleSomeEvent = () => {
// Do something, then show a notification
Hub.dispatch("notifications", {
event: "newNotification",
data: {
title: "something happened",
status: "success",
duration: 3000
}
});
}
return (
// Other components & stuff
)
};
```
### We love contributors! Is this something you'd be interested in working on?
- [ ] 👋 I may be able to implement this feature request.
- [ ] ⚠️ This feature might incur a breaking change.
Contributor guide
Research direction
Start by reviewing the proposed React Toast component and container design alongside the linked Hub utility documentation. Define the component and container behavior, including placement, status, duration, dismissal, and multiple simultaneous toasts; done means frontend notifications can be dispatched through Hub and rendered by Amplify UI.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- frontend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100