Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

variants of sonner #2254

Closed
FleetAdmiralJakob opened this issue Dec 31, 2023 · 13 comments
Closed

variants of sonner #2254

FleetAdmiralJakob opened this issue Dec 31, 2023 · 13 comments

Comments

@FleetAdmiralJakob
Copy link

An error and an success variant of sonner would be a great addition

@jrTilak
Copy link
Contributor

jrTilak commented Dec 31, 2023

Hi @FleetAdmiralJakob,

Thanks for your suggestion. You can actually already use variants. Here's an example:

   toast.success('Event has been created')
   toast.error('Event has not been created')
  // warning, info etc 

Check here for more details : https://sonner.emilkowal.ski/

And another thing, you can also style the sooner with css as well as tailwind css also, like this with Toaster component

<Toaster
  toastOptions={{
    unstyled: true,
    classNames: {
      error: 'bg-red-400',
      success: 'text-green-400',
      warning: 'text-yellow-400',
      info: 'bg-blue-400',
    },
  }}
/>

or also with toast function:

toast('Hello World', {
  unstyled: true,
  classNames: {
    toast: 'bg-blue-400',
    title: 'text-red-400 text-2xl',
    description: 'text-red-400',
    actionButton: 'bg-zinc-400',
    cancelButton: 'bg-orange-400',
    closeButton: 'bg-lime-400',
  },
});

as mentioned here in the documentation

For more advanced usages, you can directly check out the documentation:
https://sonner.emilkowal.ski/getting-started

Feel free to ask any questions if you are not satisfied with the answer.

@javed24
Copy link

javed24 commented Feb 1, 2024

@jrTilak would really appreciate some pointers in terms of what I'm missing here -

  • installed sonner through shadcn
  • using toast from sonner like so -
import { toast } from 'sonner';

//...

return(
 <Button
        onClick={() => {
          toast.error('my dummy error message', {
            unstyled: true,
            duration: 9000000,
            classNames: {
              error: 'bg-red-400',
              info: 'bg-blue-400',
              success: 'bg-green-400',
              warning: 'bg-orange-400',
              toast: 'bg-blue-400',
              title: 'text-red-400 text-2xl',
              description: 'text-red-400',
              actionButton: 'bg-zinc-400',
              cancelButton: 'bg-orange-400',
              closeButton: 'bg-lime-400',
            },
          });
        }}
      >
        <div className="flex items-center justify-center">
          <span>Show Error Toast</span>
        </div>
      </Button>
)

I understand that a lot more styles will have to go there if I'm opting for unstyled. However, it doesn't look like any of those styles are taking into action, as this is all I'm getting -

Screenshot 2024-02-01 at 11 39 58 AM

What's interesting though is that looks like only the text-2xl portion from title: 'text-red-400 text-2xl', is taking into action, but nothing else. Any thoughts on what I'm missing here?

And in case it helps, my components/ui/sonner.tsx is exactly as it is after it gets installed and following is how I've added Toaster at the global level -

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <Toaster />
      <AuthProvider>
        <RouterProvider router={router} />
      </AuthProvider>
      <ReactQueryDevtools />
    </QueryClientProvider>
  </React.StrictMode>,
);

@jrTilak
Copy link
Contributor

jrTilak commented Feb 2, 2024

Yes, You are right.

I also noticed that the styles are not being applied using the method you are using.

After doing some trials here are my findings:

  1. The classes we applying are being applied to the element but the problem is that they does not work because default styles are overwriting them.
    • Example : When wen apply bg-red-400 , the default style background-color: hsl(var(--background)); overwrites the style.
  2. You mentioned that text-2xl is working , it is because there is no default font size.
    It maybe bug or something , I guess
    The unstyled=true is not working properly maybe.
Example.tsx.-.moinulmoin_vite-react-tailwind-starter.-.StackBlitz.-.Google.Chrome.2024-02-02.11-13-32.mp4

Solution

For now you can provide the same styles to <Toaster/> instead of toast() like this and it works as expected.

<Toaster  toastOptions={{
            unstyled: true,
            duration: 9000000,
            classNames: {
              error: 'bg-red-400',
              info: 'bg-blue-400',
              success: 'bg-green-400',
              warning: 'bg-orange-400',
              toast: 'bg-blue-400',
              title: 'text-red-400 text-2xl',
              description: 'text-red-400',
              actionButton: 'bg-zinc-400',
              cancelButton: 'bg-orange-400',
              closeButton: 'bg-lime-400',
            },
          }}/>

OR,

you can directly import the <Toaster/> from sooner

import { Toaster } from 'sonner';

BUG

I think it is some bug from shadcn as sooner is working fine when we import form sooner and does not work when import form shadcn.

I guess you should open a issue, if you want.

If you are not satisfied with the answer, you can ask more❤️

@javed24
Copy link

javed24 commented Feb 2, 2024

thanks for looking into it @jrTilak , appreciate your insight!

in my case, using toaster from sonner is a better and more scalable option than the component (<Toaster/>) flavor of it. I am importing sonner directly from sonner in my component (as well as importing <Toaster/> directly from sonner in my main.tsx. I just happened to install it through shadcn. So I'm not quite sure if it's necessarily a bug from shadcn.

Having said that, I think you're right regarding there being some sort of style overriding going on. What I'm not sure about though is the source - this style overriding seems to be originating from the library itself (?), i.e., in the video, where you're inspecting the styles for the background color, it's coming from the .group.toaster class(es), which are coming from the library, right?

As a workaround, what I found working for me is the following -

toast.custom(
            (t) => {
              return (
                <div className="flex justify-between">
                  <div className="flex items-center">
                    <Alert />
                    <div className="ml-2">This is a dummy error message</div>
                  </div>
                  <Button
                    className="text-white"
                    variant="link"
                    onClick={() => toast.dismiss(t)}
                  >
                    <Cancel />
                  </Button>
                </div>
              );
            },
            {
              unstyled: true,
              duration: 9000000,
              description: 'some generic text',
              classNames: {
                toast:
                  'bg-green-100 rounded-lg py-2 px-4 shadow-lg text-white w-96',
              },
            },
          );

Basically putting all my styles in the toast class and using custom jsx.

@jrTilak
Copy link
Contributor

jrTilak commented Feb 2, 2024

Yeah, there is some style overriding , I think it is from shadcn because if you inspect the component <Toaster/> that you installed from shadcn, It has some styles overriding done using the tailwind variables to make the design consistent

<Sonner
      theme={theme as ToasterProps["theme"]}
      className="toaster group"
      toastOptions={{
        classNames: {
          toast:
            "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
          description: "group-[.toast]:text-muted-foreground",
          actionButton:
            "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
          cancelButton:
            "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
        },
      }}
      {...props}
    />

It is good things as it makes us our design consistent but it also made that drawback to overriding the styles.

As I mentioned earlier, if you pass the style props to the <Toaster/>, it works as expected because it knows you are passing the props and use the given styles but if you pass the style props from the function it has no way to know that you are passing the styles because the Toaster is from shadcn and toast function is from sooner .

That's it from me.

And glad to know you found the solution helpful.

@javed24
Copy link

javed24 commented Feb 2, 2024

yeah, that makes sense. Guess the best path forward in this case would be to use Toaster from shadcn whenever applicable (and the passed styles thru classNames will take over), and use toast from sonner in other cases and make use of the approach I've laid out above. Thanks!

@nelwincatalogo
Copy link

I prefer variant like this

image

Just add something like this to the toastOptions

// components/ui/sonner.tsx

<Sonner
      theme={theme as ToasterProps['theme']}
      className="toaster group"
      toastOptions={{
        classNames: {
         ...
          icon: 'group-data-[type=error]:text-red-500 group-data-[type=success]:text-green-500 group-data-[type=warning]:text-amber-500 group-data-[type=info]:text-blue-500',
        },
      }}
      {...props}
    />

@aryaadinulfadlan
Copy link

I prefer variant like this

image

Just add something like this to the toastOptions

// components/ui/sonner.tsx

<Sonner
      theme={theme as ToasterProps['theme']}
      className="toaster group"
      toastOptions={{
        classNames: {
         ...
          icon: 'group-data-[type=error]:text-red-500 group-data-[type=success]:text-green-500 group-data-[type=warning]:text-amber-500 group-data-[type=info]:text-blue-500',
        },
      }}
      {...props}
    />

hi sir, Where can I get all the props or properties related to this sonner?
because I need more customization

@nelwincatalogo
Copy link

I prefer variant like this
image
Just add something like this to the toastOptions

// components/ui/sonner.tsx

<Sonner
      theme={theme as ToasterProps['theme']}
      className="toaster group"
      toastOptions={{
        classNames: {
         ...
          icon: 'group-data-[type=error]:text-red-500 group-data-[type=success]:text-green-500 group-data-[type=warning]:text-amber-500 group-data-[type=info]:text-blue-500',
        },
      }}
      {...props}
    />

hi sir, Where can I get all the props or properties related to this sonner? because I need more customization

You can follow the installation guide here:
https://ui.shadcn.com/docs/components/sonner

After the installation, just paste the following code in components/ui/sonner.tsx toastOptions

icon: 'group-data-[type=error]:text-red-500 group-data-[type=success]:text-green-500 group-data-[type=warning]:text-amber-500 group-data-[type=info]:text-blue-500',

@jekigates
Copy link

jekigates commented Jul 10, 2024

// sonner.tsx
import { AlertTriangle, CheckCircle, Info, Loader, XCircle } from "lucide-react"
import { useTheme } from "next-themes"
import { Toaster as Sonner } from "sonner"

type ToasterProps = React.ComponentProps<typeof Sonner>

const Toaster = ({ ...props }: ToasterProps) => {
    const { theme = "system" } = useTheme()

    return (
        <Sonner
            theme={theme as ToasterProps["theme"]}
            className="toaster group"
            toastOptions={{
                classNames: {
                    toast: "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
                    description: "group-[.toast]:text-muted-foreground",
                    actionButton:
                        "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
                    cancelButton:
                        "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
                },
            }}
            icons={{
                success: <CheckCircle className="h-4 w-4 text-green-500" />,
                info: <Info className="h-4 w-4 text-blue-500" />,
                warning: <AlertTriangle className="h-4 w-4 text-amber-500" />,
                error: <XCircle className="h-4 w-4 text-red-500" />,
                loading: <Loader className="h-4 w-4 text-gray-500 animate-spin" />,
            }}
            {...props}
        />
    )
}

export { Toaster }

Example how to use it :

toast.success("Success", {
    description: "Profile updated successfully",
})
toast.error("Custom Title 1", {
    description: "Failed to update profile",
 }) 

@Cathykatinti
Copy link

return (
<Sonner
theme={theme as ToasterProps['theme']}
className="toaster group"
toastOptions={{
classNames: {
toast:
'group toast group-[.toaster]:bg-background group-[.toaster]:border-border group-[.toaster]:shadow-lg',
description: 'group-[.toast]:text-muted-foreground',
actionButton:
'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',
cancelButton:
'group-[.toast]:bg-muted group-[.toast]:text-muted-foreground',
error: 'bg-red-100 text-red-800 border border-red-400',
success: 'bg-green-100 text-green-800 border border-green-400',
warning: 'bg-yellow-100 text-yellow-800 border border-yellow-400',
info: 'bg-blue-100 text-blue-800 border border-blue-400',
just get rid off the default text color and everything will be oukay ,

@Cathykatinti
Copy link

text-foreground group-[.toaster] get rid of this line and all will be a success

@techcoder2007
Copy link

import type { ToasterProps } from 'sonner';

// Helper function to manage toast options and class names
export function getToastOptions(
	overrides: Partial<ToasterProps>,
): Partial<ToasterProps> {
	const defaultClassNames = {
		toast:
			'group text-sm rounded-lg p-5 min-w-64 border font-sans font-semibold toast group-[.toaster]:shadow-lg flex items-center gap-3',
		actionButton:
			'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',
		cancelButton: 'group-[.toast]:bg-muted group-[.toast]:text-muted-foreground',
		success:
			'group-[.toaster]:bg-emerald-500 group-[.toaster]:text-pale-green-100 group-[.toaster]:border-emerald-500 dark:group-[.toaster]:bg-emerald-500 dark:group-[.toaster]:border-emerald-500',
		error:
			'group-[.toaster]:bg-toast-error group-[.toaster]:text-pale-green-1000',
		warning:
			'group-[.toaster]:bg-orange-400 group-[.toaster]:text-white group-[.toaster]:border-orange-200 dark:group-[.toaster]:bg-orange-900 dark:group-[.toaster]:text-orange-100 dark:group-[.toaster]:border-orange-800',
		info:
			'group-[.toaster]:bg-blue-100 group-[.toaster]:text-blue-900 group-[.toaster]:border-blue-200 dark:group-[.toaster]:bg-blue-900 dark:group-[.toaster]:text-blue-100 dark:group-[.toaster]:border-blue-800',
	};

	return {
		...overrides,
		toastOptions: {
			...overrides.toastOptions,
			classNames: {
				...defaultClassNames,
				closeButton: 'group-[.toast]:bg-muted group-[.toast]:text-muted-foreground',
				...overrides.toastOptions?.classNames,
			},
		},
	};
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants