reactjstailwind-csstoastreact-toastify

How to customize React Toastify progress bar using tailwindcss?


I am trying to customize the original React-Toastify component using the following code:

  const bgColor = 'bg-[#F6F4E8]';
  const color = 'text-[#1D3124]';
  const progressBarBgColor = '#07bc0c';
  const borderBgColor = 'border-[#1C9099]';

  return (
    <ToastContainer
      toastClassName={() =>
        classNames(
          'relative flex p-2 min-h-10 border rounded-md justify-between overflow-hidden cursor-pointer',
          bgColor,
          color,
          borderBgColor,
        )
      }
      position="top-right"
      autoClose={3000}
      icon={<Icon />}
      closeButton={(props) => <CloseButton closeToast={props.closeToast} />}
      progressStyle={{ background: progressBarBgColor }}
    />
  );

My result was: enter image description here

It looks great, but I need to customize the "progress bar animate" section that currently appears in light green. I want to achieve this using only inline styles, as I need to be able to change the theme dynamically. I am using Tailwind CSS and would like to continue using it for this customization.

Thanks for your help.


Solution

  • The progress bar background is rendered by a different element, underneath the progress bar itself, as per the source code:

    <div
      className={`${Default.CSS_NAMESPACE}__progress-bar--wrp`}
      data-hidden={isHidden}
    >
      <div
        className={`${Default.CSS_NAMESPACE}__progress-bar--bg ${Default.CSS_NAMESPACE}__progress-bar-theme--${theme} ${Default.CSS_NAMESPACE}__progress-bar--${type}`}
      />
      <div
        role="progressbar"
        aria-hidden={isHidden ? 'true' : 'false'}
        aria-label="notification timer"
        className={classNames}
        style={style}
        {...animationEvent}
      />
    </div>
    

    From the above code, we can see that we can't pass any style attribute to the element. However, we can see that the CSS uses the --toastify-color-progress-<type> CSS variable to color the background:

    .#{$rt-namespace}__progress-bar {
      &-theme--light {
        background: var(--toastify-color-progress-light);
      }
      &-theme--dark {
        background: var(--toastify-color-progress-dark);
      }
      &--info {
        background: var(--toastify-color-progress-info);
      }
      &--success {
        background: var(--toastify-color-progress-success);
      }
      &--warning {
        background: var(--toastify-color-progress-warning);
      }
      &--error {
        background: var(--toastify-color-progress-error);
      }
      &-theme--colored#{&}--info,
      &-theme--colored#{&}--success,
      &-theme--colored#{&}--warning,
      &-theme--colored#{&}--error {
        background: var(--toastify-color-transparent);
      }
    }
    

    So we can set this CSS variable value to our own value on the parent and it will inherit down on the progress bar:

    const { ToastContainer, toast, Icons } = reactToastify;
    const classNames = x => x;
    const Icon = Icons.success;
    const CloseButton = () => 'CloseButton';
    
    function App() {
      const notify = () => toast.success('This is a magic Toast.');
      
      const bgColor = 'bg-[#F6F4E8]';
      const color = 'text-[#1D3124]';
      const progressBarBgColor = '#07bc0c';
      const borderBgColor = 'border-[#1C9099]';
    
      return (
        <React.Fragment>
          <button onClick={notify} className="bg-slate-100">Notify</button>
          <ToastContainer
            toastClassName={() =>
              classNames(
                'relative flex p-2 min-h-10 border rounded-md justify-between overflow-hidden cursor-pointer',
                bgColor,
                color,
                borderBgColor
              )
            }
            position="top-right"
            autoClose={3000}
            icon={<Icon />}
            closeButton={(props) => <CloseButton closeToast={props.closeToast} />}
            progressStyle={{ background: progressBarBgColor }}
            style={{
              '--toastify-color-progress-success': 'red',
            }}
          />
        </React.Fragment>
      );
    }
    
    ReactDOM.createRoot(document.getElementById('app')).render(<App/>);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js" integrity="sha512-QVs8Lo43F9lSuBykadDb0oSXDL/BbZ588urWVCRwSIoewQv/Ewg1f84mK3U790bZ0FfhFa1YSQUmIhG+pIRKeg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js" integrity="sha512-6a1107rTlA4gYpgHAqbwLAtxmWipBdJFcq8y5S/aTge3Bp+VAklABm2LO+Kg51vOWR9JMZq1Ovjl5tpluNpTeQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://www.unpkg.com/clsx@2.1.1/dist/clsx.min.js" integrity="sha384-dEq4EUqxSIwObxCTXRGn1G8uU8Dqce+ragCb5MYDS6s+QHC2gaYQLxHklTJLaked" crossorigin="anonymous"></script>
    <script>window.react = window.React</script>
    <script src="https://www.unpkg.com/react-toastify@10.0.5/dist/react-toastify.umd.js" integrity="sha384-axiQ+ovFSlgpLnlT3oGHKz3lWgJJLH9Si9u0aOBilM79dxWHEqsoU4Tmk3AsnfYg" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="https://www.unpkg.com/react-toastify@10.0.5/dist/ReactToastify.css" integrity="sha384-4qDaORTdDVMzUks008Hp4k0NNSvc5n/wS3ub2pkl8zdpiYIh6SjCFPecQe8ZZrnq" crossorigin="anonymous">
    <script src="https://cdn.tailwindcss.com/3.4.3"></script>
    
    <body class="bg-slate-950">
      <div id="app"></div>
    </body>

    Alternatively, you could use a Tailwind class to target and style the progress bar background directly. This would mean you would not need to match the correct type for the --toastify-color-progress-<type> CSS variable:

    const { ToastContainer, toast, Icons } = reactToastify;
    const classNames = x => x;
    const Icon = Icons.success;
    const CloseButton = () => 'CloseButton';
    
    function App() {
      const notify = () => toast.success('This is a magic Toast.');
      
      const bgColor = 'bg-[#F6F4E8]';
      const color = 'text-[#1D3124]';
      const progressBarBgColor = '#07bc0c';
      const borderBgColor = 'border-[#1C9099]';
    
      return (
        <React.Fragment>
          <button onClick={notify} className="bg-slate-100">Notify</button>
          <ToastContainer
            toastClassName={() =>
              classNames(
                'relative flex p-2 min-h-10 border rounded-md justify-between overflow-hidden cursor-pointer',
                bgColor,
                color,
                borderBgColor
              )
            }
            position="top-right"
            autoClose={3000}
            icon={<Icon />}
            closeButton={(props) => <CloseButton closeToast={props.closeToast} />}
            progressStyle={{ background: progressBarBgColor }}
            className={String.raw`[&_.Toastify\_\_progress-bar--bg]:bg-[--bg]`}
            style={{
              '--bg': 'red',
            }}
          />
        </React.Fragment>
      );
    }
    
    ReactDOM.createRoot(document.getElementById('app')).render(<App/>);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js" integrity="sha512-QVs8Lo43F9lSuBykadDb0oSXDL/BbZ588urWVCRwSIoewQv/Ewg1f84mK3U790bZ0FfhFa1YSQUmIhG+pIRKeg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js" integrity="sha512-6a1107rTlA4gYpgHAqbwLAtxmWipBdJFcq8y5S/aTge3Bp+VAklABm2LO+Kg51vOWR9JMZq1Ovjl5tpluNpTeQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://www.unpkg.com/clsx@2.1.1/dist/clsx.min.js" integrity="sha384-dEq4EUqxSIwObxCTXRGn1G8uU8Dqce+ragCb5MYDS6s+QHC2gaYQLxHklTJLaked" crossorigin="anonymous"></script>
    <script>window.react = window.React</script>
    <script src="https://www.unpkg.com/react-toastify@10.0.5/dist/react-toastify.umd.js" integrity="sha384-axiQ+ovFSlgpLnlT3oGHKz3lWgJJLH9Si9u0aOBilM79dxWHEqsoU4Tmk3AsnfYg" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="https://www.unpkg.com/react-toastify@10.0.5/dist/ReactToastify.css" integrity="sha384-4qDaORTdDVMzUks008Hp4k0NNSvc5n/wS3ub2pkl8zdpiYIh6SjCFPecQe8ZZrnq" crossorigin="anonymous">
    <script src="https://cdn.tailwindcss.com/3.4.3"></script>
    
    <body class="bg-slate-950">
      <div id="app"></div>
    </body>