<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Bishal Thapaliya</title>
    <description>The latest articles on Forem by Bishal Thapaliya (@vishalthapaliya).</description>
    <link>https://forem.com/vishalthapaliya</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F376636%2F94593ed2-a4fb-4602-83b5-0a42339707bd.jpeg</url>
      <title>Forem: Bishal Thapaliya</title>
      <link>https://forem.com/vishalthapaliya</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/vishalthapaliya"/>
    <language>en</language>
    <item>
      <title>🎨 Building a Random Gradient Generator with React (Step-by-Step Guide)</title>
      <dc:creator>Bishal Thapaliya</dc:creator>
      <pubDate>Wed, 10 Sep 2025 09:42:17 +0000</pubDate>
      <link>https://forem.com/vishalthapaliya/building-a-random-gradient-generator-with-react-step-by-step-guide-16co</link>
      <guid>https://forem.com/vishalthapaliya/building-a-random-gradient-generator-with-react-step-by-step-guide-16co</guid>
      <description>&lt;p&gt;If you’ve ever found yourself spending way too much time picking the perfect color combination for a design, this guide is for you. We’re going to build something fun, practical, and visually stunning. By the end of this step-by-step guide, you’ll be able to create a &lt;strong&gt;Random Gradient Generator&lt;/strong&gt; using &lt;strong&gt;React.js&lt;/strong&gt;, which will allow you to generate endless color gradients (linear, radial, and conic) with just one click, copy their CSS code, and use them to make your projects stand out.&lt;/p&gt;

&lt;p&gt;This guide is beginner-friendly and explains every line of code so you can learn React while building something fun and practical.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 What We’re Building
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;We’ll create a UI where users can:&lt;/li&gt;
&lt;li&gt;Choose how many gradients to generate&lt;/li&gt;
&lt;li&gt;Select the type of gradient (linear, radial, or conic)&lt;/li&gt;
&lt;li&gt;Click a button to generate random gradients&lt;/li&gt;
&lt;li&gt;Copy the CSS code for each gradient&lt;/li&gt;
&lt;li&gt;Load more gradients when available&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s a sneak peek of how it will look&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F62c3ppbpl4phj97bcr2h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F62c3ppbpl4phj97bcr2h.png" alt="image gradient generator" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📂 Project Setup&lt;/strong&gt;&lt;br&gt;
First, make sure you have a React project ready. Then, create two files inside the &lt;code&gt;src/components&lt;/code&gt; folder:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GradientGenerator.jsx&lt;/li&gt;
&lt;li&gt;GradientGenerator.css&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;📝 Writing the Component&lt;/strong&gt;&lt;br&gt;
Let’s break the GradientGenerator.jsx step by step.&lt;br&gt;
import { useEffect, useState } from "react";&lt;br&gt;
import './GradientGenerator.css';&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📝 We import React hooks (useState and useEffect) and the CSS file for styling.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  1. Setting Up State
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [num, setNum] = useState(12);
const [type, setType] = useState('linear');
const [gradientCollections, setGradientCollections] = useState([]);
const [displayCount, setDisplayCount] = useState(12);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;num&lt;/code&gt; → number of gradients to generate.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;type&lt;/code&gt; → type of gradient (&lt;code&gt;linear&lt;/code&gt;, &lt;code&gt;radial&lt;/code&gt;, &lt;code&gt;conic&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gradientCollections&lt;/code&gt; → stores all generated gradients.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;displayCount&lt;/code&gt; → how many gradients to show at once.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also calculate what to display:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const displayedGradients = gradientCollections.slice(0, displayCount);
const showLoadMore = displayCount &amp;lt; gradientCollections.length;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;📝 👉 This helps us show only a part of &lt;code&gt;gradients&lt;/code&gt; and reveal more with a “Load More Gradients” button.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. Random Color Generator
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const getHexColor = () =&amp;gt; {
  const rgb = 255 * 255 * 255;
  const random = Math.floor(Math.random() * rgb);
  const hexValue = random.toString(16);
  const colorCode = hexValue.padEnd(6, '0');
  return `#${colorCode}`;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;📝 This function creates a random HEX color code every time it’s called.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Generating Gradients
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const generateGradients = () =&amp;gt; {
  let colors = [];

  for (let i = 0; i &amp;lt; num; i++) {
    const degree = Math.floor(Math.random() * 360);
    const color1 = getHexColor();
    const color2 = getHexColor();

    if (type === 'linear') {
      colors.push({
        gradient: `linear-gradient(${degree}deg, ${color1}, ${color2})`,
        css: `background: linear-gradient(${degree}deg, ${color1}, ${color2})`
      });
    } else if (type === 'radial') {
      colors.push({
        gradient: `radial-gradient(circle, ${color1}, ${color2})`,
        css: `background: radial-gradient(circle, ${color1}, ${color2})`
      });
    } else {
      colors.push({
        gradient: `conic-gradient(from ${degree}deg, ${color1}, ${color2})`,
        css: `background: conic-gradient(from ${degree}deg, ${color1}, ${color2})`
      });
    }
  }

  setGradientCollections(colors);
  setDisplayCount(Math.min(12, num));
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;📝 Depending on the selected gradient type, we push a new gradient style into the colors array.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  4. Load More Functionality
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const loadMoreGradients = () =&amp;gt; {
  const newCount = Math.min(displayCount + 12, gradientCollections.length);
  setDisplayCount(newCount);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;📝 Each time we click the “Load More Gradients” button, it shows 12 more gradients.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  5. Copying CSS to Clipboard
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const copyCss = (css) =&amp;gt; {
  navigator.clipboard.writeText(css);

  const toast = document.createElement('div');
  toast.textContent = 'Code Copied Successfully!';
  toast.className = 'toast-notification';
  document.body.appendChild(toast);

  setTimeout(() =&amp;gt; {
    if (document.body.contains(toast)) {
      document.body.removeChild(toast);
    }
  }, 3000);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;📝 This allows users to copy the gradient CSS with a single click, and a toast message confirms success. In this section, we're creating our own custom toast notification (without using any external library).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  6. Auto-Generate Gradients on Page Load
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useEffect(() =&amp;gt; {
  generateGradients();
}, [type]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;📝 Every time the component first mounts or when the gradient type changes (linear, radial, or conic), the useEffect hook runs and triggers generateGradients(). This ensures fresh gradients are automatically generated without needing to click the button.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  7. Rendering the UI
&lt;/h3&gt;

&lt;p&gt;Now, let’s render the entire UI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return (
  &amp;lt;section className="gradient-generator-container"&amp;gt;
    &amp;lt;div className="background-elements"&amp;gt;
      &amp;lt;div className="floating-element element-1"&amp;gt;&amp;lt;/div&amp;gt;
      &amp;lt;div className="floating-element element-2"&amp;gt;&amp;lt;/div&amp;gt;
      &amp;lt;div className="floating-element element-3"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div className="content-wrapper"&amp;gt;

      &amp;lt;header className="gradient-header"&amp;gt;
        &amp;lt;div className="logo-container"&amp;gt;
          &amp;lt;div className="logo-icon"&amp;gt;🎨&amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;h1 className="main-title"&amp;gt;Random Gradient Generator&amp;lt;/h1&amp;gt;
        &amp;lt;p className="subtitle"&amp;gt;
           Create stunning gradients for your next project with 
           just one click
        &amp;lt;/p&amp;gt;
      &amp;lt;/header&amp;gt;

      &amp;lt;div className="controls"&amp;gt;
        &amp;lt;div className="control-group"&amp;gt;
          &amp;lt;input 
             type="number" 
             value={num} 
             onChange={(e) =&amp;gt; setNum(e.target.value)}
             className="number-input" /&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="control-group"&amp;gt;
          &amp;lt;select 
             value={type} 
             onChange={(e) =&amp;gt; setType(e.target.value)}
             className="select-input"&amp;gt;
             &amp;lt;option value="linear"&amp;gt;Linear&amp;lt;/option&amp;gt;
             &amp;lt;option value="radial"&amp;gt;Radial&amp;lt;/option&amp;gt;
             &amp;lt;option value="conic"&amp;gt;Conic&amp;lt;/option&amp;gt;
          &amp;lt;/select&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;button 
          onClick={generateGradients} 
          className="generate-button"&amp;gt;
           ✨ Generate
        &amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;

      &amp;lt;div className="gradient-grid"&amp;gt;
        {displayedGradients.map((color, index) =&amp;gt; (
          &amp;lt;div 
            key={index} 
            className="gradient-card" 
            style={{ background: color.gradient, animationDelay:
            `${index * 0.01}s` }}&amp;gt;
            &amp;lt;div className="overlay"&amp;gt;&amp;lt;/div&amp;gt;
            &amp;lt;div className="gradient-info"&amp;gt;
              &amp;lt;div className="gradient-type"&amp;gt;{type}&amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;button onClick={() =&amp;gt; copyCss(color.css)}
              className="copy-button"&amp;gt;
              📋 Copy
            &amp;lt;/button&amp;gt;
          &amp;lt;/div&amp;gt;
        ))}
      &amp;lt;/div&amp;gt;

      {showLoadMore &amp;amp;&amp;amp; (
        &amp;lt;div className="load-more-container"&amp;gt;
          &amp;lt;button 
             onClick={loadMoreGradients} 
             className="load-more-button"&amp;gt;
              Load More Gradients
          &amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
      )}

      &amp;lt;div className="stats-container"&amp;gt;
        &amp;lt;div className="stats-badge"&amp;gt;
          &amp;lt;span className="stats-text"&amp;gt;
            Showing 
            &amp;lt;span className="stats-number"&amp;gt;{displayCount}&amp;lt;/span&amp;gt; 
            of 
            &amp;lt;span className="stats-number"&amp;gt;
              {gradientCollections.length}
            &amp;lt;/span&amp;gt; gradients
          &amp;lt;/span&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/section&amp;gt;
);

export default GradientGenerator;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;📝 &lt;strong&gt;Here we:&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Render the header&lt;/li&gt;
&lt;li&gt;Add input controls&lt;/li&gt;
&lt;li&gt;Display generated gradients in a grid&lt;/li&gt;
&lt;li&gt;Add “Load More” and statistics section&lt;/li&gt;
&lt;li&gt;Finally, export it&lt;/li&gt;
&lt;/ul&gt;



&lt;h3&gt;
  
  
  Complete code snippet
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useEffect, useState } from "react";
import './GradientGenerator.css';

const GradientGenerator = () =&amp;gt; {
  const [num, setNum] = useState(12);
  const [type, setType] = useState('linear');
  const [gradientCollections, setGradientCollections] = useState([]);
  const [displayCount, setDisplayCount] = useState(12);

  const displayedGradients = gradientCollections.slice(0, displayCount);
  const showLoadMore = displayCount &amp;lt; gradientCollections.length;

  const getHexColor = () =&amp;gt; {
    const rgb = 255 * 255 * 255;
    const random = Math.floor(Math.random() * rgb);
    const hexValue = random.toString(16);
    const colorCode = hexValue.padEnd(6, '0');
    return `#${colorCode}`;
  };

  const generateGradients = () =&amp;gt; {
    let colors = [];

    for(let i = 0; i &amp;lt; num; i++) {
      const degree = Math.floor(Math.random() * 360);
      const color1 = getHexColor();
      const color2 = getHexColor();

      if(type === 'linear') {
        colors.push({
          gradient: `linear-gradient(${degree}deg, ${color1}, ${color2})`,
          css: `background: linear-gradient(${degree}deg, ${color1}, ${color2})`
        });
      } else if(type === 'radial') {
        colors.push({
          gradient: `radial-gradient(circle, ${color1}, ${color2})`,
          css: `background: radial-gradient(circle, ${color1}, ${color2})`
        });
      } else {
        colors.push({
          gradient: `conic-gradient(from ${degree}deg, ${color1}, ${color2})`,
          css: `background: conic-gradient(from ${degree}deg, ${color1}, ${color2})`
        })
      }
    }

    setGradientCollections(colors);
    setDisplayCount(Math.min(12, num));
  };

  const loadMoreGradients = () =&amp;gt; {
    const newCount = Math.min(displayCount + 12, gradientCollections.length);
    setDisplayCount(newCount);
  }

  const copyCss = (css) =&amp;gt; {
    navigator.clipboard.writeText(css);

    const toast = document.createElement('div');
    toast.textContent = 'Code Copied Successfully!';
    toast.className = 'toast-notification';
    document.body.appendChild(toast);

    setTimeout(() =&amp;gt; {
      if(document.body.contains(toast)) {
        document.body.removeChild(toast);
      }
    }, 3000);
  }

  useEffect(() =&amp;gt; {
    generateGradients();
  }, [type]);

  return (
    &amp;lt;section className="gradient-generator-container"&amp;gt;
      &amp;lt;div className="background-elements"&amp;gt;
        &amp;lt;div className="floating-element element-1"&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;div className="floating-element element-2"&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;div className="floating-element element-3"&amp;gt;&amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;

      &amp;lt;div className="content-wrapper"&amp;gt;
        &amp;lt;header className="gradient-header"&amp;gt;
          &amp;lt;div className="logo-container"&amp;gt;
            &amp;lt;div className="logo-icon"&amp;gt;🎨&amp;lt;/div&amp;gt;
          &amp;lt;/div&amp;gt;
          &amp;lt;h1 className="main-title"&amp;gt;Random Gradient Generator&amp;lt;/h1&amp;gt;
          &amp;lt;p className="subtitle"&amp;gt;Create stunning gradients for your next project with just one click&amp;lt;/p&amp;gt;
        &amp;lt;/header&amp;gt;

        &amp;lt;div className="controls"&amp;gt;
          &amp;lt;div className="control-group"&amp;gt;
            &amp;lt;input type="number" value={num} onChange={(e) =&amp;gt; setNum(e.target.value)} className="number-input"/&amp;gt;
          &amp;lt;/div&amp;gt;

          &amp;lt;div className="control-group"&amp;gt;
            &amp;lt;select value={type} onChange={(e) =&amp;gt; setType(e.target.value)} className="select-input"&amp;gt;
              &amp;lt;option value="linear"&amp;gt;Linear&amp;lt;/option&amp;gt;
              &amp;lt;option value="radial"&amp;gt;Radial&amp;lt;/option&amp;gt;
              &amp;lt;option value="Conic"&amp;gt;Conic&amp;lt;/option&amp;gt;
            &amp;lt;/select&amp;gt;
          &amp;lt;/div&amp;gt;

          &amp;lt;button onClick={generateGradients} className="generate-button"&amp;gt;✨ Generate&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="gradient-grid"&amp;gt;
          { displayedGradients.map((color, index) =&amp;gt; (
            &amp;lt;div key={index} className="gradient-card" style={{ background: color.gradient, animationDelay: `${index * 0.01}s`}}&amp;gt;
              &amp;lt;div className="overlay"&amp;gt;&amp;lt;/div&amp;gt;
              &amp;lt;div className="gradient-info"&amp;gt;
                &amp;lt;div className="gradient-type"&amp;gt;{type}&amp;lt;/div&amp;gt;
              &amp;lt;/div&amp;gt;
              &amp;lt;button onClick={() =&amp;gt; copyCss(color.css)} className="copy-button"&amp;gt;📋 Copy&amp;lt;/button&amp;gt;
            &amp;lt;/div&amp;gt;
          ))}
        &amp;lt;/div&amp;gt;

        { showLoadMore &amp;amp;&amp;amp; (
          &amp;lt;div className="load-more-container"&amp;gt;
            &amp;lt;button onClick={loadMoreGradients} className="load-more-button"&amp;gt;Load More Gradients&amp;lt;/button&amp;gt;
          &amp;lt;/div&amp;gt;
        )}

        &amp;lt;div className="stats-container"&amp;gt;
          &amp;lt;div className="stats-badege"&amp;gt;
            &amp;lt;span className="stats-text"&amp;gt;
              Showing 
              &amp;lt;span className="stats-number"&amp;gt;{displayCount}&amp;lt;/span&amp;gt; of {' '} 
              &amp;lt;span className="stats-number"&amp;gt;{gradientCollections.length}&amp;lt;/span&amp;gt; gradient colors
            &amp;lt;/span&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/section&amp;gt;
  )
}

export default GradientGenerator;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  8. Styling with CSS 🎨
&lt;/h3&gt;

&lt;p&gt;All the animations, hover effects, and responsive design come from the GradientGenerator.css file. It includes:&lt;br&gt;
Background animations (floating cir&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cles, glowing effects)&lt;/li&gt;
&lt;li&gt;Grid layout for gradients&lt;/li&gt;
&lt;li&gt;Hover states with smooth animations&lt;/li&gt;
&lt;li&gt;A toast notification for copied code&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;📝 You can find the full CSS in the code here.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.gradient-generator-container {
  min-height: 100vh;
  background: linear-gradient(135deg, hsl(240, 10%, 3.9%) 0%, hsl(240, 10%, 3.9%) 50%, hsl(240, 10%, 6%) 100%);
  padding: 1rem;
  position: relative;
  overflow-x: hidden;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
  color: hsl(0, 0%, 98%);
}

@media (min-width: 640px) {
  .gradient-generator-container {
    padding: 2rem;
  }
}

.background-elements {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: hidden;
  z-index: 0;
}

.floating-element {
  position: absolute;
  width: 18rem;
  height: 18rem;
  border-radius: 50%;
  mix-blend-mode: multiply;
  filter: blur(40px);
  opacity: 0.2;
  animation: float 3s ease-in-out infinite;
}

.element-1 {
  top: 5rem;
  left: 2.5rem;
  background: linear-gradient(135deg, hsl(270, 80%, 60%), hsl(300, 80%, 65%));
  animation-delay: 0s;
}

.element-2 {
  top: 10rem;
  right: 2.5rem;
  background: linear-gradient(135deg, hsl(195, 100%, 60%), hsl(270, 80%, 60%));
  animation-delay: 2s;
}

.element-3 {
  bottom: -2rem;
  left: 5rem;
  background: linear-gradient(135deg, hsl(240, 80%, 55%), hsl(270, 80%, 60%));
  animation-delay: 4s;
}

@keyframes float {
  0%, 100% {
    transform: translateY(0px);
  }
  50% {
    transform: translateY(-2.5rem);
  }
}

.content-wrapper {
  position: relative;
  max-width: 112rem;
  margin: 0 auto;
  z-index: 1;
}

.gradient-generator-container {
  text-align: center;
  animation: slide-up 0.6s cubic-bezier(0.23, 1, 0.32, 1);
}

.logo-container {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.75rem;
  background: linear-gradient(135deg, hsl(270, 80%, 60%), hsl(300, 80%, 65%));
  border-radius: 1rem;
  margin-bottom: 1.5rem;
  box-shadow: 0 0 40px hsl(270, 80%, 60% / 0.3);
  animation: glow 2s ease-in-out infinite alternate;
}

.logo-icon {
  font-size: 2.5rem;
}

.main-title {
  font-size: 2.5rem;
  font-weight: 700;
  background: linear-gradient(135deg, hsl(270, 80%, 60%), hsl(195, 100%, 60%), hsl(270, 80%, 60%));
  background-size: 300%;
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  margin-bottom: 1rem;
  line-height: 1.2;
  animation: gradient-shift 8s ease-in-out infinite;
}

@media (min-width: 640px) {
  .main-title {
    font-size: 3.75rem;
  }
}

.subtitle {
  font-size: 1.25rem;
  color: hsl(240, 5%, 65%);
  max-width: 100%;
  margin: 0 auto;
  margin-bottom: 2rem;
}

.controls {
  display: flex;
  justify-content: center;
  margin-bottom: 3rem;
  animation: fade-in 0.6s cubic-bezier(0.23, 1, 0.32, 1);
  animation-delay: 0.2s;
  animation-fill-mode: both;
  gap: 0.75rem;
}

.control-group {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
}

.input-wrapper,
.select-wrapper {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
}

.number-input,
.select-input {
  padding: 0.8rem 1rem;
  border-radius: 0.5rem;
  border: 2px solid hsl(240, 10%, 15% / 0.5);
  background: hsl(240, 10%, 6% / 0.8);
  backdrop-filter: blur(12px);
  color: hsl(262, 93%, 12%);
  font-size: 1rem;
  font-weight: 500;
  outline: none;
  transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
  text-align: center;
  min-height: 2.5rem;
}

.number-input {
  width: 5rem;
}

.select-input {
  width: 10rem;
  appearance: none;
  cursor: pointer;
  padding-right: 2.5rem;
}

.number-input:focus,
.select-input:focus {
  border-color: hsl(270, 80%, 60%);
  box-shadow: 0 0 0 4px hsl(270, 80%, 60% / 0.2);
  background: hsl(240, 10%, 8% / 0.9);
}

.generate-button {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  padding: 0.5rem 1.5rem;
  border-radius: 0.5rem;
  border: none;
  background: linear-gradient(135deg, hsl(270, 80%, 60%), hsl(300, 80%, 65%));
  color: hsl(0, 0%, 98%);
  font-size: 1.1rem;
  font-weight: 700;
  cursor: pointer;
  transition: all 0.4s cubic-bezier(0.23, 1, 0.32, 1);
  box-shadow: 
    0 8px 25px -8px hsl(270, 80%, 60% / 0.4),
    0 0 0 1px hsl(270, 80%, 60% / 0.1);
  overflow: hidden;
}

.generate-button:hover {
  transform: translateY(-2px) scale(1.02);
  box-shadow: 
    0 12px 35px -8px hsl(270, 80%, 60% / 0.5),
    0 0 0 1px hsl(270, 80%, 60% / 0.2);
}

.generate-button:active {
  transform: translateY(0) scale(0.98);
}

.number-input:focus-visible,
.select-input:focus-visible,
.generate-button:focus-visible {
  outline: 2px solid hsl(270, 80%, 60%);
  outline-offset: 2px;
}

@media (max-width: 767px) {

  .generate-button {
    padding: 1rem 2rem;
    font-size: 1rem;
    width: 100%;
    max-width: 12rem;
  }

  .number-input,
  .select-input {
    padding: 0.875rem 1rem;
    min-height: 3rem;
  }

  .select-input {
    width: 9rem;
  }
}

.gradient-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
  margin-bottom: 3rem;
}

@media (min-width: 640px) {
  .gradient-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {
  .gradient-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

.gradient-card {
  position: relative;
  height: 12rem;
  border-radius: 1rem;
  overflow: hidden;
  box-shadow: 0 20px 40px -12px hsl(240, 10%, 0% / 0.5);
  transition: all 0.5s ease;
  animation: scale-in 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
  animation-fill-mode: both;
  backdrop-filter: blur(8px);
  border: 1px solid hsl(240, 10%, 15% / 0.2);
  cursor: pointer;
}

.gradient-card:hover {
  transform: translateY(-0.5rem) scale(1.05);
  box-shadow: 0 0 40px hsl(270, 80%, 60% / 0.3);
}

.card-overlay {
  position: absolute;
  inset: 0;
  background: hsl(0, 0%, 0% / 0);
  transition: all 0.3s ease;
}

.gradient-card:hover .card-overlay {
  background: hsl(0, 0%, 0% / 0.2);
}

.copy-button {
  position: absolute;
  bottom: 1rem;
  right: 1rem;
  padding: 0.5rem 0.75rem;
  border-radius: 0.5rem;
  border: 1px solid hsl(0, 0%, 100% / 0.2);
  background: hsl(0, 0%, 100% / 0.1);
  backdrop-filter: blur(12px);
  color: rgb(15, 3, 95);
  font-size: 0.875rem;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.3s ease;
  opacity: 0;
  transform: translateY(0.5rem);
}

.gradient-card:hover .copy-button {
  opacity: 1;
  transform: translateY(0);
}

.copy-button:hover {
  background: hsl(0, 0%, 100% / 0.2);
}

.gradient-info {
  position: absolute;
  bottom: 1rem;
  left: 1rem;
  opacity: 0;
  transition: all 0.3s ease;
  transform: translateY(0.5rem);
}

.gradient-card:hover .gradient-info {
  opacity: 1;
  transform: translateY(0);
}

.gradient-type {
  background: hsl(0, 0%, 100% / 0.1);
  backdrop-filter: blur(12px);
  border-radius: 0.5rem;
  padding: 0.25rem 0.75rem;
  border: 1px solid hsl(0, 0%, 100% / 0.2);
  color: white;
  font-size: 0.875rem;
  font-weight: 500;
  text-transform: capitalize;
}

/* Load more section */
.load-more-container {
  text-align: center;
  margin-bottom: 2rem;
  animation: fade-in 0.6s cubic-bezier(0.23, 1, 0.32, 1);
}

.load-more-button {
  padding: 0.75rem 2rem;
  border-radius: 0.75rem;
  border: 1px solid hsl(240, 10%, 15% / 0.5);
  background: hsl(240, 10%, 6% / 0.5);
  backdrop-filter: blur(8px);
  color: hsl(260, 94%, 6%);
  font-size: 1rem;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.3s ease;
}

.load-more-button:hover {
  background: hsl(240, 10%, 6% / 0.8);
  border-color: hsl(270, 80%, 60% / 0.5);
  transform: scale(1.05);
}

/* Stats section */
.stats-container {
  text-align: center;
  animation: fade-in 0.6s cubic-bezier(0.23, 1, 0.32, 1);
}

.stats-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  background: hsl(240, 10%, 6% / 0.3);
  backdrop-filter: blur(8px);
  border-radius: 9999px;
  padding: 0.75rem 1.5rem;
  border: 1px solid hsl(240, 10%, 15% / 0.2);
}

.stats-text {
  font-size: 0.875rem;
  color: hsl(240, 5%, 65%);
}

.stats-number {
  font-weight: 600;
  color: hsl(0, 0%, 98%);
}

/* Toast notification */
.toast-notification {
  position: fixed;
  top: 2rem;
  right: 2rem;
  background: hsl(240, 10%, 6%);
  color: hsl(0, 0%, 98%);
  padding: 1rem 1.5rem;
  border-radius: 0.75rem;
  border: 1px solid hsl(240, 10%, 15%);
  box-shadow: 0 20px 40px -12px hsl(240, 10%, 0% / 0.5);
  z-index: 1000;
  animation: toast-slide-in 0.3s ease-out;
}

/* Animations */
@keyframes slide-up {
  0% {
    opacity: 0;
    transform: translateY(2.5rem);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes fade-in {
  0% {
    opacity: 0;
    transform: translateY(1.25rem);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes scale-in {
  0% {
    opacity: 0;
    transform: scale(0.8);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

@keyframes glow {
  0% {
    filter: brightness(1) drop-shadow(0 0 20px hsl(270, 80%, 60% / 0.3));
  }
  100% {
    filter: brightness(1.1) drop-shadow(0 0 30px hsl(270, 80%, 60% / 0.5));
  }
}

@keyframes gradient-shift {
  0%, 100% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
}

@keyframes toast-slide-in {
  0% {
    opacity: 0;
    transform: translateX(100%);
  }
  100% {
    opacity: 1;
    transform: translateX(0);
  }
}

/* Responsive adjustments */
@media (max-width: 767px) {
  .gradient-card {
    height: 11.25rem;
  }

  .main-title {
    font-size: 2rem;
  }

  .floating-element {
    width: 12rem;
    height: 12rem;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Now you can import &lt;code&gt;GradientGenerator.jsx&lt;/code&gt; in your &lt;code&gt;App.jsx&lt;/code&gt; file and use it like any other React component.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Key Learnings&lt;/strong&gt;&lt;br&gt;
We’ve built a Random Gradient Generator in React from scratch. This project helps you practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React state management &lt;code&gt;(useState)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Lifecycle hooks &lt;code&gt;(useEffect)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Dynamic rendering with &lt;code&gt;.map()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Copying text to clipboard&lt;/li&gt;
&lt;li&gt;Styling with CSS animations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploy it on &lt;strong&gt;Netlify&lt;/strong&gt; or &lt;strong&gt;Vercel&lt;/strong&gt; and share with friends 🎉&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🚀 Wrapping Up
&lt;/h3&gt;

&lt;p&gt;In this guide, we built a &lt;strong&gt;Random Gradient Generator&lt;/strong&gt; in React that creates stunning gradients with just one click. From generating random HEX colors to copying CSS with a custom toast notification, we kept things simple and focused on the fundamentals. 🎨✨&lt;/p&gt;

&lt;p&gt;The cool part? 💡 We did it all with the basics: &lt;code&gt;useState&lt;/code&gt;, &lt;code&gt;useEffect&lt;/code&gt;, some simple logic, and a bit of &lt;code&gt;CSS&lt;/code&gt; magic. Nothing too fancy, but enough to make something that actually feels useful (and pretty cool to play with).&lt;/p&gt;

&lt;p&gt;If you made it this far, I’d love to hear your thoughts, feedback, or suggestions for improvement.&lt;/p&gt;

&lt;p&gt;Let’s keep learning, experimenting, and building awesome stuff together. 🚀&lt;/p&gt;

&lt;p&gt;Happy Coding! 💻💖&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>🚀 Build an Infinite Scroll App in React like a Pro</title>
      <dc:creator>Bishal Thapaliya</dc:creator>
      <pubDate>Fri, 16 May 2025 13:59:16 +0000</pubDate>
      <link>https://forem.com/vishalthapaliya/build-an-infinite-scroll-app-in-react-like-a-pro-9je</link>
      <guid>https://forem.com/vishalthapaliya/build-an-infinite-scroll-app-in-react-like-a-pro-9je</guid>
      <description>&lt;p&gt;Infinite scrolling is probably one of the most widely used features in today's web applications. Rather than relying on traditional pagination, it loads further content dynamically when users scroll. In this tutorial, you will learn how to implement a basic and simple Infinite Scroll component in React JS by fetching GitHub users from the GitHub API.🎯&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📝🔰 Perfect for beginners! This guide focuses on the core logic without overwhelming you with complex React patterns.&lt;br&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  🎯What We Will Build
&lt;/h2&gt;

&lt;p&gt;We will build a clean React application showing GitHub users as cards. When users scroll, additional users will be fetched automatically, providing an overall smooth browsing experience.&lt;/p&gt;

&lt;p&gt;🛠 &lt;strong&gt;Tech Stack:&lt;/strong&gt;&lt;br&gt;
⚛️ &lt;code&gt;useState&lt;/code&gt; to manage state&lt;/p&gt;

&lt;p&gt;⚛️ &lt;code&gt;useEffect&lt;/code&gt; to handle side effects like API calls and event listeners&lt;/p&gt;

&lt;p&gt;🌐 &lt;code&gt;fetch API&lt;/code&gt; to load data&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  📜 Step-by-Step Implementation&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;1️⃣ &lt;strong&gt;Project Setup and Initial Imports&lt;/strong&gt;&lt;br&gt;
Ensure your React project is set up. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📝 Tools like Vite ⚡️ make the process super fast.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Make a &lt;code&gt;components&lt;/code&gt; directory inside the &lt;code&gt;src&lt;/code&gt; folder, and create 2 files in it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;InfiniteScroll.jsx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;InfiniteScroll.css&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Import Essentials:&lt;/strong&gt;&lt;br&gt;
Open &lt;code&gt;InfiniteScroll.jsx&lt;/code&gt; file and start with the following imports.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useEffect, useState } from 'react'
import './InfiniteScroll.css'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the given code snippet above, we are importing &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt; from &lt;code&gt;React&lt;/code&gt;, and we are importing a CSS file to style the user cards later.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
2️⃣ &lt;strong&gt;States Configuration&lt;/strong&gt;&lt;br&gt;
We shall manage three primary pieces of state:&lt;/p&gt;

&lt;p&gt;👥 &lt;code&gt;users&lt;/code&gt; – stores the fetched users.&lt;/p&gt;

&lt;p&gt;📄 &lt;code&gt;page&lt;/code&gt; – track the current page.&lt;/p&gt;

&lt;p&gt;🔄 &lt;code&gt;isLoading&lt;/code&gt; – prevents multiple simultaneous API calls.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [users, setUsers] = useState([]);
const [page, setPage] = useState(1);
const [isLoading, setIsLoading] = useState(false);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;&lt;br&gt;
3️⃣ &lt;strong&gt;Fetch Users from GitHub API&lt;/strong&gt;&lt;br&gt;
We are creating an &lt;strong&gt;&lt;em&gt;async&lt;/em&gt;&lt;/strong&gt; function, which allows us to use the &lt;strong&gt;&lt;em&gt;await&lt;/em&gt;&lt;/strong&gt; keyword in it. Using &lt;em&gt;async&lt;/em&gt; makes it easier to write asynchronous code, which improves readability.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;getUsersFromAPI()&lt;/code&gt; function makes an asynchronous request to the GitHub API to retrieve a list of users, using the current page number to paginate the results.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When the data is successfully received, it adds the new users to the existing list and sets the next page number for retrieval.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If there is any exception in the process, it catches the exception and logs it to the console for debugging.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The function always stops the loading indicator, whether it is successful or not, to update the user interface accordingly.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const getUsersFromAPI = async () =&amp;gt; {
    try {
        setIsLoading(true);
        const response = await fetch(`https://api.github.com/users?since=${(page - 1) * 30}`);
        const data = await response.json();
        setUsers((prevUsers) =&amp;gt; [...prevUsers, ...data]);
        setPage((prevPage) =&amp;gt; prevPage + 1);
    } catch (error) {
        console.error(`Error while fetching users: ${error}`);
    } finally {
        setIsLoading(false);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;br&gt;&lt;br&gt;
4️⃣ &lt;strong&gt;Handle Scroll Events&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We will create a function called &lt;code&gt;handleScroll&lt;/code&gt;, which checks if the user is near the bottom of the page. If yes, it will invoke the  &lt;code&gt;getUsersFromAPI()&lt;/code&gt; function to fetch more users.&lt;br&gt;
It also ensures that, as a request is in progress, no new request is sent (isLoading prevents this).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const handleScroll = () =&amp;gt; {
    if (isLoading) return;
    if (window.innerHeight + window.scrollY &amp;gt;= document.body.offsetHeight - 10) {
        getUsersFromAPI();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;&lt;br&gt;
5️⃣ &lt;strong&gt;Setup Lifecycle with useEffect&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;useEffect&lt;/code&gt; hook runs once when the component is mounted. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It makes a call to the &lt;code&gt;getUsersFromAPI()&lt;/code&gt; method to load the first list of users.&lt;/li&gt;
&lt;li&gt;Adds a scroll event listener.&lt;/li&gt;
&lt;li&gt;Cleans the listener when the component is removed.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useEffect(() =&amp;gt; {
    getUsersFromAPI();
    window.addEventListener('scroll', handleScroll);

    return () =&amp;gt; {
        window.removeEventListener('scroll', handleScroll);
    }
}, []);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;br&gt;&lt;br&gt;
6️⃣ &lt;strong&gt;Render Users in Card Format&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We iterate over the &lt;strong&gt;&lt;em&gt;users&lt;/em&gt;&lt;/strong&gt; array using the &lt;code&gt;map()&lt;/code&gt; function and display each user in a stylish card layout. Each card displays the user's &lt;em&gt;avatar&lt;/em&gt;, &lt;em&gt;username&lt;/em&gt;, and &lt;em&gt;account type&lt;/em&gt; (i.e., User or Organization), and a &lt;em&gt;link&lt;/em&gt; to their GitHub profile is displayed when the card is hovered over.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{users.map((user) =&amp;gt; (
    &amp;lt;div className="card" key={user.id}&amp;gt;
        &amp;lt;div className="image-container"&amp;gt;
            &amp;lt;img src={user.avatar_url} alt={user.login} /&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div className="content-container"&amp;gt;
            &amp;lt;div className="contentBx"&amp;gt;
                &amp;lt;h3&amp;gt;
                    {user.login}&amp;lt;br /&amp;gt;
                    &amp;lt;span&amp;gt;{user.type}&amp;lt;/span&amp;gt;
                &amp;lt;/h3&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div className="sci"&amp;gt;
                &amp;lt;a href={user.html_url} target='blank' rel='noopener noreferrer'&amp;gt;🔗 View Profile&amp;lt;/a&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
))}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Complete code snippet&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useEffect, useState } from 'react'
import './InfiniteScroll.css'


const InfiniteScroll = () =&amp;gt; {
    const [users, setUsers] = useState([]);
    const [page, setPage] = useState(1);
    const [isLoading, setIsLoading] = useState(false);

    // function to fecth users from Github API
    const getUsersFromAPI = async () =&amp;gt; {
        try {
            setIsLoading(true);
            const response = await fetch(`https://api.github.com/users?since=${(page - 1) * 30}`);
            const data = await response.json();
            setUsers((prevUsers) =&amp;gt; [...prevUsers, ...data]);
            setPage((prevPage) =&amp;gt; prevPage + 1);
        } catch (error) {
            console.error(`Error while fetching users: ${error}`);
        } finally {
            setIsLoading(false);
        }
    }

    // function to check scroll position and load more if needed
    const handleScroll = () =&amp;gt; {
        if (isLoading) return;

        if (window.innerHeight + window.scrollY &amp;gt;= document.body.offsetHeight - 10) {
            getUsersFromAPI();
        }
    }

    // Initial load and attach scroll listener
    useEffect(() =&amp;gt; {
        getUsersFromAPI();
        window.addEventListener('scroll', handleScroll);

        return () =&amp;gt; {
            window.removeEventListener('scroll', handleScroll);
        }
    }, []);

    return (
        &amp;lt;&amp;gt;
            &amp;lt;h1 className='page-title'&amp;gt;Github Users&amp;lt;/h1&amp;gt;
            &amp;lt;section&amp;gt;
                &amp;lt;div className="container"&amp;gt;
                    {users.map((user) =&amp;gt; (
                        &amp;lt;div className="card" key={user.id}&amp;gt;
                            &amp;lt;div className="image-container"&amp;gt;
                                &amp;lt;img src={user.avatar_url} alt={user.login} /&amp;gt;
                            &amp;lt;/div&amp;gt;

                            &amp;lt;div className="content-container"&amp;gt;
                                &amp;lt;div className="content"&amp;gt;
                                    &amp;lt;h3&amp;gt;
                                        {user.login}&amp;lt;br /&amp;gt;
                                        &amp;lt;span&amp;gt;{user.type}&amp;lt;/span&amp;gt;
                                    &amp;lt;/h3&amp;gt;
                                &amp;lt;/div&amp;gt;
                                &amp;lt;div className="social"&amp;gt;
                                    &amp;lt;a href={user.html_url} target='blank' rel='noopener noreferrer'&amp;gt;View Profile&amp;lt;/a&amp;gt;
                                &amp;lt;/div&amp;gt;
                            &amp;lt;/div&amp;gt;
                        &amp;lt;/div&amp;gt;
                    ))}
                &amp;lt;/div&amp;gt;
            &amp;lt;/section&amp;gt;
        &amp;lt;/&amp;gt;
    )
}
export default InfiniteScroll
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;&lt;br&gt;
7️⃣ &lt;strong&gt;Styling with CSS&lt;/strong&gt; 💅🎨&lt;/p&gt;

&lt;p&gt;CSS is essential for creating engaging user interfaces and enhancing the look and feel of your components.&lt;/p&gt;

&lt;p&gt;For styling the &lt;strong&gt;&lt;em&gt;InfiniteScroll&lt;/em&gt;&lt;/strong&gt; component, simply copy the provided CSS code and paste it into your &lt;strong&gt;&lt;em&gt;InfiniteScroll.css&lt;/em&gt;&lt;/strong&gt; file.&lt;/p&gt;

&lt;p&gt;Feel free to customize and experiment with the styles to match your app's design preferences. 🖌️&lt;/p&gt;

&lt;p&gt;➡️ In this tutorial, I am using nested CSS, a modern and in-demand trend that improves code readability and maintains cleaner structures, especially when working on component-based designs.&lt;br&gt;&lt;br&gt;
However, if you prefer, you can always stick to the traditional flat CSS syntax, which works just as well. The choice depends on your project needs and personal preference. ✨&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.page-title {
  text-align: center;
  margin: 20px;
}

.container {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  gap: 20px;
  padding: 20px;

  .card {
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    width: 250px;
    height: 200px;
    overflow: hidden;
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
    border-radius: 15px;

    &amp;amp;:hover .content-container {
      bottom: 0;
      transition-delay: 0s;
      cursor: pointer;
    }

    &amp;amp;:hover .content-container .content h3 {
        opacity: 1;
        transform: translateY(0px);
    }

    &amp;amp;:hover .content-container .social {
        transform: translateY(0px);
        opacity: 1;
        border: 1px solid #867cc1;
        padding: 5px;
        border-radius: 10px;
    }

    .image-container {
        position: relative;
        height: 100%;
        width: 100%;

        img {
            height: 100%;
            width: 100%;
            object-fit: cover;
        }
    }


    .content-container {
      position: absolute;
      bottom: -135px;
      width: 100%;
      height: 125px;
      display: flex;
      justify-content: center;
      align-items: center;
      z-index: 10;
      flex-direction: column;
      backdrop-filter: blur(15px);
      box-shadow: 0 -10px 10px rgba(0, 0, 0, 0.1);
      border: 1px solid rgba(255, 255, 255, 0.2);
      transition: bottom 0.5s;
      transition-delay: 0.3s;


      .content {
        h3 {
        color: #fff;
        text-transform: capitalize;
        letter-spacing: 2px;
        font-weight: bold;
        font-size: 18px;
        text-align: center;
        margin: 10px 0 5px;
        line-height: 1.1em;
        transition: 0.5s;
        opacity: 0;
        transform: translateY(-20px);
        transition-delay: 0.5s;
        }

        span {
            font-size: 12px;
            font-weight: 300;
            text-transform: initial;
        }
      }


      .social {
            position: relative;
            bottom: 0x;
            display: flex;
            transform: translateY(40px);
            opacity: 0;
            transition-delay: 0.3s;

            a {
                color: #d3d3d3;
                font-size: 15px;
                text-decoration: none;
            }
        }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;&lt;br&gt;
💡 &lt;strong&gt;Key Learnings&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✅ &lt;code&gt;useState&lt;/code&gt; – &lt;em&gt;To manage data, page number, and loading state&lt;/em&gt;&lt;br&gt;
✅ &lt;code&gt;useEffect&lt;/code&gt; – &lt;em&gt;To handle side-effects and lifecycle events like API calls and scroll listeners&lt;/em&gt;&lt;br&gt;
✅ &lt;code&gt;fetch API&lt;/code&gt; – &lt;em&gt;To make HTTP requests to the GitHub API&lt;/em&gt;&lt;br&gt;
✅ &lt;code&gt;map()&lt;/code&gt; – &lt;em&gt;To dynamically render user cards&lt;/em&gt;&lt;br&gt;
✅ Scroll Event – &lt;em&gt;To detect when the user reaches to the bottom of the page&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
🚀 &lt;strong&gt;Wrapping Up&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this tutorial, we explored how to build a smooth infinite scroll feature in React JS, pulling real-time data from the GitHub API and presenting it in an elegant card layout. 🃏✨&lt;/p&gt;

&lt;p&gt;The focus was on keeping the code clean and beginner-friendly, sticking to the core React hooks like &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt; without diving into complex patterns.&lt;/p&gt;

&lt;p&gt;By following along, you now have a solid understanding of how state management, side effects, and event listeners can work together to create engaging, dynamic user experiences. 💡&lt;/p&gt;

&lt;p&gt;If you made it this far, I’d love to hear your feedback or if there's anything you think I could have explained better.&lt;/p&gt;

&lt;p&gt;Let’s keep learning together! 🚀&lt;/p&gt;

&lt;p&gt;Happy Coding! 👨‍💻👩‍💻💖&lt;/p&gt;

</description>
      <category>react</category>
      <category>frontend</category>
      <category>webdev</category>
      <category>coding</category>
    </item>
    <item>
      <title>🚀 Build a Smooth &amp; Performant Image Carousel in React – A Beginner’s Guide</title>
      <dc:creator>Bishal Thapaliya</dc:creator>
      <pubDate>Thu, 01 May 2025 16:29:37 +0000</pubDate>
      <link>https://forem.com/vishalthapaliya/build-a-smooth-performant-image-carousel-in-react-a-beginners-guide-48ji</link>
      <guid>https://forem.com/vishalthapaliya/build-a-smooth-performant-image-carousel-in-react-a-beginners-guide-48ji</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqknyvrgd5u1tzg57723x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqknyvrgd5u1tzg57723x.png" alt="banner image" width="800" height="585"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re learning React and want to create a clean, responsive, and performant image carousel, you’re in the right place! In this guide, we’ll walk through building a React image carousel with auto-sliding functionality, navigation buttons, and efficient state management.&lt;/p&gt;

&lt;p&gt;Whether you're enhancing your portfolio or contributing to a real-world project, understanding how to build this component will sharpen your skills in React, state, effects, and component re-rendering.&lt;/p&gt;

&lt;p&gt;Let’s dive in! 🧠&lt;/p&gt;

&lt;h3&gt;
  
  
  🧱 Step 1: Project Setup and Imports
&lt;/h3&gt;

&lt;p&gt;Before we dive in, I’ll assume that you already have your React development environment set up and your project is running smoothly. If you haven't started yet, &lt;a href="https://vite.dev/guide/" rel="noopener noreferrer"&gt;Vite&lt;/a&gt; is an excellent tool to begin with.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📝 &lt;strong&gt;Note:&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;create-react-app&lt;/em&gt;&lt;/strong&gt; (CRA) is now officially deprecated and no longer recommended for new projects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once your React project is ready, follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Inside your &lt;strong&gt;&lt;em&gt;src&lt;/em&gt;&lt;/strong&gt; folder, create a new folder named &lt;strong&gt;&lt;em&gt;components&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside the &lt;strong&gt;&lt;em&gt;components&lt;/em&gt;&lt;/strong&gt; folder, create a new file: 👉 &lt;strong&gt;&lt;em&gt;ImageCarousel.jsx&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create an &lt;strong&gt;&lt;em&gt;ImageCarousel.css&lt;/em&gt;&lt;/strong&gt; file in the same folder to handle styling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now, open &lt;strong&gt;&lt;em&gt;ImageCarousel.jsx&lt;/em&gt;&lt;/strong&gt; and start with the following imports:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useEffect, useState } from 'react';
import './ImageCarousel.css';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  🔍 The importance of this is:
&lt;/h4&gt;

&lt;p&gt;We import &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;useState&lt;/code&gt; to track the current image index.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;useEffect&lt;/code&gt; allows us to handle the auto-slide behavior.&lt;/li&gt;
&lt;li&gt;Separating CSS into &lt;strong&gt;&lt;em&gt;ImageCarousel.css&lt;/em&gt;&lt;/strong&gt; helps keep JSX clean and your styles modular, promoting maintainability and scalability.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🖼️Step 2: Prepare the Image Dataset
&lt;/h3&gt;

&lt;p&gt;We’re using random high-resolution images from &lt;a href="https://www.pexels.com/" rel="noopener noreferrer"&gt;Pexels&lt;/a&gt; — a free stock photo website. Always remember to credit such sources when using their content, even in demos or projects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const images = [
    { id: 1, url: "https://images.pexels.com/photos/29089597/pexels-photo-29089597/free-photo-of-stunning-autumn-beach-sunset-with-waves.jpeg?auto=compress&amp;amp;cs=tinysrgb&amp;amp;w=1260&amp;amp;h=750&amp;amp;dpr=2"},
    { id: 2, url: "https://images.pexels.com/photos/691668/pexels-photo-691668.jpeg"},
    { id: 3, url: "https://images.pexels.com/photos/2049422/pexels-photo-2049422.jpeg?auto=compress&amp;amp;cs=tinysrgb&amp;amp;w=1260&amp;amp;h=750&amp;amp;dpr=2"},
    { id: 4, url: "https://images.pexels.com/photos/325044/pexels-photo-325044.jpeg?auto=compress&amp;amp;cs=tinysrgb&amp;amp;w=1260&amp;amp;h=750&amp;amp;dpr=2"},
    { id: 5, url: "https://images.pexels.com/photos/1485894/pexels-photo-1485894.jpeg?auto=compress&amp;amp;cs=tinysrgb&amp;amp;w=1260&amp;amp;h=750&amp;amp;dpr=2"},
];

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Each image object has:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;code&gt;id&lt;/code&gt;: Used as a unique key for React.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;url&lt;/code&gt;: The direct link to the image.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By using an array of objects, you keep your code clean and make it easy to render the images dynamically using &lt;code&gt;.map()&lt;/code&gt; function later. This structure makes it easy to loop through and render dynamically, which is more scalable than hardcoding images into JSX.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; Separating data into its own file is a best practice and usually recommended; however, this example keeps it together for convenience.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  🎯 Step 3: Managing the Current Image State
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [currentImageIndex, setCurrentImageIndex] = useState(0);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Understanding the relevance:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Core Functionality&lt;/em&gt;&lt;/strong&gt;: The &lt;code&gt;useState&lt;/code&gt; React hook is used to manage the &lt;code&gt;currentImageIndex&lt;/code&gt;, which determines the visible image.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Initial State&lt;/em&gt;&lt;/strong&gt;: Setting &lt;code&gt;currentImageIndex&lt;/code&gt; to &lt;code&gt;0&lt;/code&gt; ensures the first image is displayed upon loading.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Dynamic Control&lt;/em&gt;&lt;/strong&gt;: The &lt;code&gt;setCurrentImageIndex&lt;/code&gt; function, provided by &lt;code&gt;useState&lt;/code&gt;, allows for changing the displayed image due to user navigation or auto-play functionality.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⬅️➡️ Step 4: Previous &amp;amp; Next Navigation Handlers
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const handlePreviousClick = () =&amp;gt; {
    setCurrentImageIndex(
        currentImageIndex === 0 ? images.length - 1 : currentImageIndex - 1
    );
};

const handleNextClick = () =&amp;gt; {
    setCurrentImageIndex((currentImageIndex + 1) % images.length);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🧠 Let’s break this down in simple terms:&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;em&gt;Previous&lt;/em&gt;&lt;/strong&gt; button checks:&lt;br&gt;
👉 “Am I on the first image (index &lt;code&gt;0&lt;/code&gt;)? If &lt;strong&gt;&lt;em&gt;yes&lt;/em&gt;&lt;/strong&gt;, go to the last image. If &lt;strong&gt;&lt;em&gt;not&lt;/em&gt;&lt;/strong&gt;, go one step back.”&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;em&gt;Next&lt;/em&gt;&lt;/strong&gt; button uses the modulo operator (&lt;code&gt;%&lt;/code&gt;), which is a super helpful trick:&lt;br&gt;
👉 &lt;code&gt;(currentIndex + 1) % totalImages&lt;/code&gt; ensures that when you’re at the last image, it loops back to the first one automatically.&lt;/p&gt;
&lt;h4&gt;
  
  
  🏆 Why it’s a best practice:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Avoids &lt;code&gt;if-else&lt;/code&gt; chains and long logic blocks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Makes sure the index never goes out of bounds, avoiding crashes or &lt;code&gt;undefined&lt;/code&gt; behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keeps the carousel experience circular and smooth, especially important for user engagement.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  ⏱️ Step 5: Auto-Sliding with useEffect
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useEffect(() =&amp;gt; {
    const timer = setTimeout(() =&amp;gt; {
        handleNextClick();
    }, 5000);

    return () =&amp;gt; clearTimeout(timer);
}, [currentImageIndex]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Explanation
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;useEffect&lt;/code&gt; is a React hook that runs every time the &lt;code&gt;currentImageIndex&lt;/code&gt; changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inside it, we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Start a timer using &lt;code&gt;setTimeout&lt;/code&gt; that waits for 5 seconds (5000ms).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After 5 seconds, it calls &lt;code&gt;handleNextClick()&lt;/code&gt; function, moving to the next image.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We also return a cleanup function &lt;code&gt;(clearTimeout)&lt;/code&gt; to cancel the old &lt;code&gt;timer&lt;/code&gt; if the image changes before the timeout finishes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  🧠 Why this approach?
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Using &lt;code&gt;setTimeout&lt;/code&gt; inside &lt;code&gt;useEffect&lt;/code&gt; lets us create controlled, one-time delays, which is safer and easier to debug than using &lt;code&gt;setInterval&lt;/code&gt;, which repeats endlessly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cleanup prevents memory leaks and ensures only one timer runs at a time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Makes your carousel auto-slide lightweight and reliable without draining performance.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  🧩 Step 6: Rendering the JSX
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return (
    &amp;lt;section&amp;gt;
        &amp;lt;h2&amp;gt;React Image Carousel&amp;lt;/h2&amp;gt;

        &amp;lt;div className="image-container"&amp;gt;
            &amp;lt;button className="nav-button left" onClick={handlePreviousClick}&amp;gt;&amp;amp;lt;&amp;lt;/button&amp;gt;

            {images.map((image, index) =&amp;gt; (
                &amp;lt;img 
                    src={image.url} 
                    alt="images" 
                    className={ currentImageIndex === index ? 'block' : 'hidden'}
                    key={image.id} 
                /&amp;gt;
            ))}

            &amp;lt;button className="nav-button right" onClick={handleNextClick}&amp;gt;&amp;amp;gt;&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/section&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  👇 Key Takeaways:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Navigation buttons on either side call their respective functions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;images.map()&lt;/code&gt; dynamically renders each image.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We use a conditional class:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Only the current image is set to &lt;code&gt;display: block&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;All others are hidden with &lt;code&gt;display: none&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We use &lt;code&gt;key={image.id}&lt;/code&gt; to help React track which items changed, improving performance.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Complete code snippet
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useEffect, useState } from 'react';
import './ImageCarousel.css';

// images from pexels.com
const images = [
    { id: 1, url: "https://images.pexels.com/photos/29089597/pexels-photo-29089597/free-photo-of-stunning-autumn-beach-sunset-with-waves.jpeg?auto=compress&amp;amp;cs=tinysrgb&amp;amp;w=1260&amp;amp;h=750&amp;amp;dpr=2"},
    { id: 2, url: "https://images.pexels.com/photos/691668/pexels-photo-691668.jpeg"},
    { id: 3, url: "https://images.pexels.com/photos/2049422/pexels-photo-2049422.jpeg?auto=compress&amp;amp;cs=tinysrgb&amp;amp;w=1260&amp;amp;h=750&amp;amp;dpr=2"},
    { id: 4, url: "https://images.pexels.com/photos/325044/pexels-photo-325044.jpeg?auto=compress&amp;amp;cs=tinysrgb&amp;amp;w=1260&amp;amp;h=750&amp;amp;dpr=2"},
    { id: 5, url: "https://images.pexels.com/photos/1485894/pexels-photo-1485894.jpeg?auto=compress&amp;amp;cs=tinysrgb&amp;amp;w=1260&amp;amp;h=750&amp;amp;dpr=2"},
]

const ImageCarousel = () =&amp;gt; {
    const [currentImageIndex, setCurrentImageIndex] = useState(0);

    const handlePreviousClick = () =&amp;gt; {
        setCurrentImageIndex(
            currentImageIndex === 0 ? images.length - 1 : currentImageIndex - 1
        );
    };

    const handleNextClick = () =&amp;gt; {
        setCurrentImageIndex((currentImageIndex + 1) % images.length);
    };

    useEffect(() =&amp;gt; {
        const timer = setTimeout(() =&amp;gt; {
            handleNextClick();
        }, 5000);

        return () =&amp;gt; clearTimeout(timer);
    }, [currentImageIndex]);

    return (
        &amp;lt;section&amp;gt;
            &amp;lt;h2&amp;gt;React Image Carousel&amp;lt;/h2&amp;gt;

            &amp;lt;div className="image-container"&amp;gt;
                &amp;lt;button className="nav-button left" onClick={handlePreviousClick}&amp;gt;&amp;amp;lt;&amp;lt;/button&amp;gt;

                {images.map((image, index) =&amp;gt; (
                    &amp;lt;img 
                        src={image.url} 
                        alt="images" 
                        className={ currentImageIndex === index ? 'block' : 'hidden'}
                        key={image.id} 
                    /&amp;gt;
                ))}

                &amp;lt;button className="nav-button right" onClick={handleNextClick}&amp;gt;&amp;amp;gt;&amp;lt;/button&amp;gt;

            &amp;lt;/div&amp;gt;
        &amp;lt;/section&amp;gt;
    )
}

export default ImageCarousel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  💅 Step 7: Styling with CSS
&lt;/h3&gt;

&lt;p&gt;For effective web development and UI enhancement, CSS is indispensable. The CSS provided is a custom implementation, and you have the flexibility to define your own styles.&lt;/p&gt;

&lt;p&gt;For styling your image carousel, take the provided CSS code and paste it into the &lt;strong&gt;&lt;em&gt;ImageCarousel.css&lt;/em&gt;&lt;/strong&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;section {
    height: 100vh;
    width: 100vw;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    background-color: #f9fafb;
    text-align: center;
}

h2 {
  font-size: 2rem;
  color: #1f2937;
  margin-bottom: 1.5rem;
}

.image-container {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  max-width: 800px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 1rem;
  background-color: #fff;
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.08);
  height: 500px;
}

.image-container img {
  max-width: 100%;
  max-height: 100%;
  width: 100%;
  border-radius: 0.75rem;
  object-fit: cover;
  transition: opacity 0.5s ease, transform 0.5s ease;
}

img.hidden {
  display: none;
}

img.block {
  display: block;
  animation: fadeIn 0.6s ease;
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: scale(0.98);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

.nav-button {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  background-color: rgba(0, 0, 0, 0.4);
  color: #fff;
  border: none;
  border-radius: 50%;
  font-size: 1.5rem;
  font-weight: normal;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0.8;
  transition: background-color 0.3s ease, opacity 0.3s ease;
  padding: 0;
  line-height: 1;
  z-index: 1;
}

.nav-button.left {
  left: 1rem;
}

.nav-button.right {
  right: 1rem;
}

.nav-button:hover {
  background-color: rgba(255, 255, 255, 0.6);
  opacity: 1;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🚀 Final Thoughts &amp;amp; Optimizations
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;✅ Best Practices Recap:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Clean state management with &lt;code&gt;useState&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Safe and performant effects with &lt;code&gt;useEffect&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Modular, dynamic rendering using &lt;code&gt;.map()&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Looping logic via the modulo operator for easy circular navigation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🙌 Conclusion
&lt;/h3&gt;

&lt;p&gt;This easy-to-understand image carousel is a great way to learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;React Hooks (&lt;code&gt;useState&lt;/code&gt;, &lt;code&gt;useEffect&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Conditional rendering&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Auto-slide behavior&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clean, modular component architecture&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to try it and experiment with your own styles and animations!&lt;/p&gt;

&lt;p&gt;If you've had a chance to read this carefully, I'd appreciate it if you could mention anything I might have missed explaining.&lt;/p&gt;

&lt;p&gt;Happy coding 😀&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Build a Custom Clock Widget in Bonita UI Designer</title>
      <dc:creator>Bishal Thapaliya</dc:creator>
      <pubDate>Wed, 09 Jun 2021 13:54:44 +0000</pubDate>
      <link>https://forem.com/vishalthapaliya/build-a-custom-clock-widget-in-bonita-ui-designer-1617</link>
      <guid>https://forem.com/vishalthapaliya/build-a-custom-clock-widget-in-bonita-ui-designer-1617</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhrkz5vq9tlvaicbfq12p.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhrkz5vq9tlvaicbfq12p.gif" alt="Banner image" width="512" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A web widget is a component that can be used as a feature on a web page or application. In this article, I will explain how to create a custom analog clock widget in Bonita UI Designer. You’ll see how to create an analog clock widget, change the appearance of the widget when you drag and drop it onto the whiteboard in Bonita UI Designer, and how to add some CSS and JavaScript to make the clock widget functional to the end-users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a clock widget and define its appearance
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Step 1: Get started
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Go to the Bonita UI Designer home page.&lt;/li&gt;
&lt;li&gt;Click on the &lt;strong&gt;Create&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Custom widget&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Give an appropriate name to the widget (eg. AnalogClock).&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Create&lt;/strong&gt;.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3x2ntjyx1fl3wb5uazb8.PNG" alt="Step 1 image" width="510" height="592"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The custom widget editor window will appear. A custom widget is composed of six sections: &lt;strong&gt;Description&lt;/strong&gt;, &lt;strong&gt;Template&lt;/strong&gt;, &lt;strong&gt;Controller&lt;/strong&gt;, &lt;strong&gt;Assets&lt;/strong&gt;, &lt;strong&gt;Required angular modules&lt;/strong&gt;, and &lt;strong&gt;Properties&lt;/strong&gt;. For this custom widget, we will make some modifications in the &lt;strong&gt;Description&lt;/strong&gt;, &lt;strong&gt;Template&lt;/strong&gt;, &lt;strong&gt;Controller&lt;/strong&gt;, and &lt;strong&gt;Assets&lt;/strong&gt; sections only.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk5o245x6wlev7qghwdu7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk5o245x6wlev7qghwdu7.png" alt="Step 1.1 image" width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 2: Remove default information
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Remove everything from all the sections. We are going to create this widget from scratch.&lt;/li&gt;
&lt;li&gt;Now, the widget editor window looks like this:
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7p6z8z1yru0j1d5t3p2r.png" alt="Step 2 image" width="800" height="511"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Step 3: Set the description
&lt;/h4&gt;

&lt;p&gt;In the description section, describe the widget and its behavior. This description will be shown when we hover over the widget in the custom widget list.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the &lt;strong&gt;Description&lt;/strong&gt; section, write the basic information about the widget. For example;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;“This is a custom analog clock widget built with UI Designer which is useful to display the current time.”&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F30vf74qkb8cnfcdt0lch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F30vf74qkb8cnfcdt0lch.png" alt="Step 3 image" width="800" height="132"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 4: Define the Template section
&lt;/h4&gt;

&lt;p&gt;In this step, we define how the widget will be displayed in the UI Designer whiteboard. We are going to add some HTML markup to display a clock SVG image only when the "environment" variable is defined, i.e. we are in the UID whiteboard.&lt;/p&gt;

&lt;p&gt;In Step 8 we will add more HTML markup to deal with how the widget should be rendered at runtime, i.e. when the page is actually displayed in an application.&lt;/p&gt;

&lt;p&gt;In the template section, write the following HTML and CSS codes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTML&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div ng-if="environment"&amp;gt;
    &amp;lt;svg xmlns='http://www.w3.org/2000/svg' version='1.0' viewBox='0 0 798.000000 794.000000' preserveAspectRatio='xMidYMid meet' style='&amp;amp;#10;'&amp;gt;
        &amp;lt;g transform='translate(0.000000,794.000000) scale(0.100000,-0.100000)' fill='#000' stroke='none'&amp;gt;
            &amp;lt;path d='M3680 7869 c-478 -39 -951 -166 -1378 -370 -187 -89 -294 -150 -482 -275 -221 -146 -400 -293 -595 -489 -322 -321 -571 -672 -764 -1077 -507 -1060 -507 -2296 0 -3356 89 -187 150 -294 275 -482 146 -221 293 -400 489 -595 321 -322 672 -571 1077 -764 1060 -507 2296 -507 3356 0 187 89 294 150 482 275 221 146 400 293 595 489 322 321 571 672 764 1077 507 1060 507 2296 0 3356 -89 187 -150 294 -275 482 -146 221 -293 400 -489 595 -321 322 -672 571 -1077 764 -609 291 -1316 423 -1978 370z m730 -214 c715 -85 1386 -375 1947 -840 138 -115 343 -320 458 -458 468 -564 753 -1228 842 -1957 24 -202 24 -638 0 -840 -52 -429 -162 -803 -349 -1190 -465 -965 -1316 -1672 -2358 -1960 -148 -41 -380 -86 -550 -107 -202 -24 -638 -24 -840 0 -429 52 -803 162 -1190 349 -965 465 -1672 1316 -1960 2358 -41 148 -86 380 -107 550 -24 202 -24 638 0 840 52 429 162 803 349 1190 465 965 1316 1672 2358 1960 207 58 479 103 735 124 109 8 536 -3 665 -19z'/&amp;gt;
            &amp;lt;path d='M3942 7218 c-17 -17 -17 -259 0 -276 7 -7 24 -12 38 -12 45 0 50 15 50 150 0 135 -5 150 -50 150 -14 0 -31 -5 -38 -12z'/&amp;gt;
            &amp;lt;path d='M3724 5860 c-32 -13 -64 -59 -64 -92 0 -16 45 -390 100 -831 56 -441 100 -815 98 -832 -2 -20 -8 -29 -18 -27 -8 1 -638 280 -1398 618 -761 339 -1390 613 -1398 610 -8 -3 -14 -14 -14 -24 0 -16 244 -128 1373 -631 l1372 -611 -1211 0 c-1160 0 -1212 -1 -1227 -18 -22 -24 -21 -65 1 -85 17 -16 119 -17 1258 -17 l1239 0 17 -30 c19 -33 86 -70 128 -70 42 0 108 37 130 72 42 68 35 139 -20 201 -27 32 -28 34 -129 857 -56 454 -106 836 -110 850 -8 27 -64 70 -90 69 -9 0 -26 -4 -37 -9z m316 -1775 c16 -9 36 -29 45 -45 31 -60 10 -137 -45 -165 -110 -57 -222 55 -165 165 29 55 105 76 165 45z'/&amp;gt;
            &amp;lt;path d='M742 4018 c-15 -15 -15 -61 0 -76 8 -8 53 -12 138 -12 135 0 150 5 150 50 0 45 -15 50 -150 50 -85 0 -130 -4 -138 -12z'/&amp;gt;
            &amp;lt;path d='M6942 4018 c-7 -7 -12 -24 -12 -38 0 -45 15 -50 150 -50 135 0 150 5 150 50 0 45 -15 50 -150 50 -85 0 -130 -4 -138 -12z'/&amp;gt;
            &amp;lt;path d='M3942 1018 c-17 -17 -17 -259 0 -276 7 -7 24 -12 38 -12 45 0 50 15 50 150 0 85 -4 130 -12 138 -15 15 -61 15 -76 0z'/&amp;gt;
        &amp;lt;/g&amp;gt;
    &amp;lt;/svg&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; In the HTML code above, ng-if=”environment” detects that the widget is displayed within the UI Designer whiteboard. This defines how the widget is displayed to the developer within the UI Designer (as opposed to now the widget displayed to the user within a web page at runtime). Additionally, the &lt;code&gt;&amp;lt;svg&amp;gt;&amp;lt;/svg&amp;gt;&lt;/code&gt; tag is used as an SVG image container to draw the paths that generate a clock image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSS&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;style&amp;gt;
    svg {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 50%;
        width: 50%;
        margin: 0 auto;
    }
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The CSS codes must be written inside the &lt;code&gt;&amp;lt;style&amp;gt;&amp;lt;/style&amp;gt;&lt;/code&gt; tag.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6n3bulsjuh9owkp2aoxg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6n3bulsjuh9owkp2aoxg.png" alt="Step 4 image" width="800" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on the Save button.&lt;/li&gt;
&lt;li&gt;We have successfully created a new analog clock widget.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Step 5: Pro tip - Define the widget icon (optional)
&lt;/h4&gt;

&lt;p&gt;It is not mandatory, but useful, to give a realistic look and feel to the analog clock widget icon when it appears on the list of a custom widget. To do this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the “customAnalogClockWidget.json” file located inside the Bonita workspace (eg. /workspace/My project/web_widgets/customAnalogClock/customAnalogClock.json).&lt;/li&gt;
&lt;li&gt;Copy and paste the given code below after the “template” line inside the “customAnalogClock.json”.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;SVG icon for the widget&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"icon": "&amp;lt;svg xmlns='http://www.w3.org/2000/svg' version='1.0' viewBox='0 0 798.000000 794.000000' preserveAspectRatio='xMidYMid meet' style='&amp;amp;#10;'&amp;gt;&amp;lt;g transform='translate(0.000000,794.000000) scale(0.100000,-0.100000)' fill='#fff' stroke='none'&amp;gt;&amp;lt;path d='M3680 7869 c-478 -39 -951 -166 -1378 -370 -187 -89 -294 -150 -482 -275 -221 -146 -400 -293 -595 -489 -322 -321 -571 -672 -764 -1077 -507 -1060 -507 -2296 0 -3356 89 -187 150 -294 275 -482 146 -221 293 -400 489 -595 321 -322 672 -571 1077 -764 1060 -507 2296 -507 3356 0 187 89 294 150 482 275 221 146 400 293 595 489 322 321 571 672 764 1077 507 1060 507 2296 0 3356 -89 187 -150 294 -275 482 -146 221 -293 400 -489 595 -321 322 -672 571 -1077 764 -609 291 -1316 423 -1978 370z m730 -214 c715 -85 1386 -375 1947 -840 138 -115 343 -320 458 -458 468 -564 753 -1228 842 -1957 24 -202 24 -638 0 -840 -52 -429 -162 -803 -349 -1190 -465 -965 -1316 -1672 -2358 -1960 -148 -41 -380 -86 -550 -107 -202 -24 -638 -24 -840 0 -429 52 -803 162 -1190 349 -965 465 -1672 1316 -1960 2358 -41 148 -86 380 -107 550 -24 202 -24 638 0 840 52 429 162 803 349 1190 465 965 1316 1672 2358 1960 207 58 479 103 735 124 109 8 536 -3 665 -19z'/&amp;gt;&amp;lt;path d='M3942 7218 c-17 -17 -17 -259 0 -276 7 -7 24 -12 38 -12 45 0 50 15 50 150 0 135 -5 150 -50 150 -14 0 -31 -5 -38 -12z'/&amp;gt;&amp;lt;path d='M3724 5860 c-32 -13 -64 -59 -64 -92 0 -16 45 -390 100 -831 56 -441 100 -815 98 -832 -2 -20 -8 -29 -18 -27 -8 1 -638 280 -1398 618 -761 339 -1390 613 -1398 610 -8 -3 -14 -14 -14 -24 0 -16 244 -128 1373 -631 l1372 -611 -1211 0 c-1160 0 -1212 -1 -1227 -18 -22 -24 -21 -65 1 -85 17 -16 119 -17 1258 -17 l1239 0 17 -30 c19 -33 86 -70 128 -70 42 0 108 37 130 72 42 68 35 139 -20 201 -27 32 -28 34 -129 857 -56 454 -106 836 -110 850 -8 27 -64 70 -90 69 -9 0 -26 -4 -37 -9z m316 -1775 c16 -9 36 -29 45 -45 31 -60 10 -137 -45 -165 -110 -57 -222 55 -165 165 29 55 105 76 165 45z'/&amp;gt;&amp;lt;path d='M742 4018 c-15 -15 -15 -61 0 -76 8 -8 53 -12 138 -12 135 0 150 5 150 50 0 45 -15 50 -150 50 -85 0 -130 -4 -138 -12z'/&amp;gt;&amp;lt;path d='M6942 4018 c-7 -7 -12 -24 -12 -38 0 -45 15 -50 150 -50 135 0 150 5 150 50 0 45 -15 50 -150 50 -85 0 -130 -4 -138 -12z'/&amp;gt;&amp;lt;path d='M3942 1018 c-17 -17 -17 -259 0 -276 7 -7 24 -12 38 -12 45 0 50 15 50 150 0 85 -4 130 -12 138 -15 15 -61 15 -76 0z'/&amp;gt;&amp;lt;/g&amp;gt;&amp;lt;/svg&amp;gt;",
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjelr8ptdsh1r5m1dybji.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjelr8ptdsh1r5m1dybji.png" alt="Step 5 image" width="800" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The SVG code generates a clock icon for this widget. Make sure to keep the comma (,) at the end of the line.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Save the file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We have now successfully changed the icon of the widget. Now, it's time to use this custom widget inside an application page and check if the clock widget has the correct icon and the display when it is placed onto the whiteboard.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 6: Check the widget
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Go to the Bonita UI Designer home page.&lt;/li&gt;
&lt;li&gt;Click on the &lt;strong&gt;Create&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Application page&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Name the page (eg. ClockPage).&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Create&lt;/strong&gt;.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqt7jkl3hk4l3ap4ilep7.png" alt="Step 6 image" width="508" height="590"&gt;
&lt;/li&gt;
&lt;li&gt;The ClockPage editor window will open.&lt;/li&gt;
&lt;li&gt;Now, in the page editor window, click on the &lt;strong&gt;Custom widgets&lt;/strong&gt; tab  on the left.&lt;/li&gt;
&lt;li&gt;The AnalogClock widget appears in the list and has a clock image as an icon.&lt;/li&gt;
&lt;li&gt;Drag and drop the clock widget onto the whiteboard.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Output
&lt;/h4&gt;

&lt;p&gt;The widget on the whiteboard will look like this:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmkraf86lda2b3vk5y5vf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmkraf86lda2b3vk5y5vf.png" alt="Step 6 output image" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have completed the definition of the custom analog clock widget, and now we are going to make the clock widget functional to end-users.&lt;/p&gt;
&lt;h3&gt;
  
  
  Make the widget functional to the end-users
&lt;/h3&gt;

&lt;p&gt;The implementation steps that follow are based on a large device screen resolution (i.e., screen width &amp;gt;= 1200px). You can change the responsiveness of the page by clicking on thedevice screen size icon that appears on the top right corner in Bonita UI Designer.&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 7: Edit the widget
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Click and select the custom &lt;strong&gt;AnalogClock&lt;/strong&gt; widget on the whiteboard.&lt;/li&gt;
&lt;li&gt;Click on the &lt;strong&gt;“...”&lt;/strong&gt; button next to the widget name on the right.&lt;/li&gt;
&lt;li&gt;Click on Edit. 
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6t03dsu3yy0yqubcsg9i.png" alt="Step 7 image" width="800" height="334"&gt;
&lt;/li&gt;
&lt;li&gt;The widget editor window will appear.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Step 8: Define the Template
&lt;/h4&gt;

&lt;p&gt;In the template section in the widget editor window, write the HTML for the widget that will be displayed to the users at runtime. Write the following HTML code after the closing of &lt;code&gt;&amp;lt;div ng-if=”environment”&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTML&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="clockFace" ng-if="!environment"&amp;gt;
    &amp;lt;div class="hour"&amp;gt;
        &amp;lt;div class="hourHand"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class="minute"&amp;gt;
        &amp;lt;div class="minuteHand"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class="second"&amp;gt;
        &amp;lt;div class="secondHand"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; In the HTML code above, ng-if=”!environment” detects that the widget is to be displayed to the user within a web page at runtime.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftr3nlmaqval4smr6nu6i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftr3nlmaqval4smr6nu6i.png" alt="Step 8 image" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 9: Add Assets
&lt;/h4&gt;

&lt;p&gt;The Assets section is defined to import the resources (image, CSS, JS) required for the widget. For the clock widget, we will add only an image and a CSS file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clock face image&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download the clock image from this &lt;a href="https://drive.google.com/file/d/1QTtewQNBG_Ii1UszARyXjnXZwvEViTjR/view?usp=sharing" rel="noopener noreferrer"&gt;link&lt;/a&gt; here. (image source: Google)&lt;/li&gt;
&lt;li&gt;Go to the AnalogClock widget editor window in the Bonita UI Designer and click on the Add button in the &lt;strong&gt;Assets&lt;/strong&gt; section to upload the image file.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcad8pnf0bawxppbd6imk.png" alt="Step 9 image" width="752" height="480"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This clock face image file will be used as a background-image property in the CSS clock class. You can use the image URL directly or download and add as an asset.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSS&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a CSS file somewhere on your computer (e.g., D:\analog-clock-widget.css) and copy the following CSS code into it:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.clock-container {
    display: flex;
    justify-content: center;
    align-items: center;
}

.clockFace {
    position: relative;
    width: 150px;
    height: 150px;
    display: flex;
    justify-content: center;
    align-items: center;
background-image: url(../img/clock-face.png);
    background-color: #0A4561;
    background-size: cover;
    border: 3px solid #fff;
    border-radius: 50%;
  box-shadow: 0 10px 10px rgba(0, 0, 0, 0.3), 
             inset 0 10px 10px rgba(0, 0, 0, 0.3);
}

.clockFace:before {
    content: '';
    width: 14px;
    height: 14px;
    background: #fff;
    border-radius: 50%;
    z-index: 10000;
}
.clockFace .hour,
.clockFace .minute,
.clockFace .second {
    position: absolute;
}

.clockFace .hour,
.hourHand {
    height: 90px;
}

.clockFace .minute,
.minuteHand {
    height: 105px;
}

.clockFace .second,
.secondHand {
    height: 120px;
}

.hourHand,
.minuteHand,
.secondHand {
    display: flex;
    justify-content: center;
}

.hourHand:before {
    content: '';
    width: 6px;
    height: 50px;
    background: #B52A2A;
    z-index: 10;
    border-radius: 6px 6px 0 0;
}

.minuteHand:before {
    content: '';
    width: 4px;
    height: 60px;
    background: #fff;
    z-index: 11;
    border-radius: 6px 6px 0 0;
}

.secondHand:before {
    content: '';
    width: 2px;
    height: 80px;
    background: #fff;
    z-index: 12;
    border-radius: 6px 6px 0 0;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Some CSS properties such as height, width, background-color, position, etc. can be defined as you wish. In the CSS code above, “.hr:before”, “mn-before”, and “.sc:before” are defined to create hour hand, minute hand, and second hand respectively.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Save the CSS file and close it.&lt;/li&gt;
&lt;li&gt;Go to the AnalogClock widget editor window in the Bonita UI Designer and click on the Add button in the &lt;strong&gt;Assets&lt;/strong&gt; section to upload this CSS file.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F16fb5ijzmiykke7us5c9.png" alt="Step 9 image 2" width="739" height="466"&gt;
&lt;/li&gt;
&lt;li&gt;As we have added all the required resources, now the Assets section will look like this:
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9tvfyw1ciimrg1ksrxjc.png" alt="Step 9 image 3" width="784" height="275"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 10: Set the Controller
&lt;/h4&gt;

&lt;p&gt;The Controller section is dedicated to implementing the javascript required to make the widget functional.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the Controller section, write the following javascript code.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function ($scope) {
    setInterval(() =&amp;gt; {
    const degree = 6;
    let day = new Date();
    let hour = day.getHours() * 30;
    let minute = day.getMinutes() * degree;
    let second = day.getSeconds() * degree;

document.getElementsByClassName('hourHand').item(0).style.transform = `rotate(${(hour)+(minute/12)}deg)`;
document.getElementsByClassName('minuteHand').item(0).style.transform = `rotate(${minute}deg)`;
document.getElementsByClassName('secondHand').item(0).style.transform = `rotate(${second}deg)`;
    });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; All the javascript code needs to be wrapped inside the function ($scope){} method that augments the AngularJS scope and exposes functions that we can use in the template. &lt;/p&gt;

&lt;p&gt;In the code above, we are defining a variable called degree and assigning the value 6 to it, and using the variable to define the minute and second. It is used to rotate the minute hand and the second hand by 6 degrees. Similarly, the hour hand changes its position by 30 degrees when the hour changes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Now the controller section will look like this:
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxise400txmzgii461ggd.png" alt="Step 10 image" width="800" height="267"&gt;
&lt;/li&gt;
&lt;li&gt;Click on the Save button to save all the modifications applied to the widget.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Add the custom analog clock to a page
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Step 11: Add and set the widget properties
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Go back to the Bonita UI Designer home page.&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;ClockPage&lt;/strong&gt; (the page we created previously).&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clean the page if there is already a widget on it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Drag and drop a Title widget onto the whiteboard and set the properties as shown below:&lt;br&gt;
Text = Analog Clock Widget&lt;br&gt;
Title level = Level 2&lt;br&gt;
Alignment = Center&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy91n59lznwc9rjpqvnwj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy91n59lznwc9rjpqvnwj.png" alt="Step 11 image" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Drag and drop a container widget below the title widget and set the property Width = 4.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figo6eqfe9hytq2173s95.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figo6eqfe9hytq2173s95.png" alt="Step 11 image 2" width="800" height="260"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on the &lt;strong&gt;Custom widgets&lt;/strong&gt; tab on the left.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The AnalogClock widget appears in the list, and the icon is a the clock that we defined in the pro-tip step.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Drag and drop the AnalogClock widget next to the container widget and set the properties:&lt;br&gt;
Width = 4&lt;br&gt;
CSS classes = clock-container&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fifyg7q7hmozim738sd2f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fifyg7q7hmozim738sd2f.png" alt="Step 11 image 3" width="800" height="196"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Drag and drop a container widget next to the clock widget and set the property Width = 4.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqn9e8i80s9uxbfio6ij7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqn9e8i80s9uxbfio6ij7.png" alt="Step 11 image 4" width="800" height="260"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save the page and click on Preview to see the result.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Output
&lt;/h3&gt;

&lt;p&gt;When you click on the preview button, you will see a clock displaying the current time on your browser.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq6oxgw9xikbotp4ztrqr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq6oxgw9xikbotp4ztrqr.gif" alt="Final result image" width="550" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Congratulations&lt;/strong&gt;, you have successfully built your own analog clock widget!&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftdcj9fjvqnwip7xeabai.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftdcj9fjvqnwip7xeabai.gif" alt="Hurray image" width="480" height="320"&gt;&lt;/a&gt;&lt;br&gt;
I will explain in another upcoming article how we can define some properties of the clock widget that will allow us to use the same widget to display the time based on different time zones.&lt;/p&gt;

&lt;p&gt;I would love to know what other kinds of custom widgets you would like to implement with Bonita UI Designer. Please share your tips and examples.&lt;/p&gt;

&lt;p&gt;Stay tuned. Have fun with Bonita!&lt;/p&gt;

</description>
      <category>bonitasoft</category>
      <category>uidesigner</category>
      <category>customwidget</category>
    </item>
    <item>
      <title>Build a Custom Search Widget in Bonita UI Designer</title>
      <dc:creator>Bishal Thapaliya</dc:creator>
      <pubDate>Thu, 15 Oct 2020 09:24:43 +0000</pubDate>
      <link>https://forem.com/vishalthapaliya/build-a-custom-search-widget-in-bonita-ui-designer-4m0j</link>
      <guid>https://forem.com/vishalthapaliya/build-a-custom-search-widget-in-bonita-ui-designer-4m0j</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fh6h6ris7b5n4ls1wvjww.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fh6h6ris7b5n4ls1wvjww.gif" alt="Banner image" width="450" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a web developer, I love to provide users with good UX. In my opinion, this means, at the minimum, to have consistent pages, layouts, and consistent widgets within pages. When I can’t find the right widget in the toolkit provided, I create my own to be sure I can build a UX I can be proud of. As a side benefit, having widgets tailored to my needs saves my time and effort and allows me to be more efficient at my work. &lt;/p&gt;

&lt;p&gt;In this article, I am going to explain how to create a custom search widget in Bonita UI Designer. This article has 2 parts. The first part explains how to create a search widget and change the appearance of the widget when we drag and drop it onto the whiteboard in Bonita UI Designer.&lt;/p&gt;

&lt;p&gt;The second part explains how to add some CSS to make the search widget functional to the end-users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Part I: Define the appearance of your custom widget
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Step 1
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Go to the Bonita UI Designer home page.&lt;/li&gt;
&lt;li&gt;Click on the &lt;em&gt;Create&lt;/em&gt; button.&lt;/li&gt;
&lt;li&gt;Choose &lt;em&gt;Custom widget&lt;/em&gt; in the &lt;strong&gt;Type&lt;/strong&gt; section.&lt;/li&gt;
&lt;li&gt;Give a proper name to the widget (eg. searchWidget).&lt;/li&gt;
&lt;li&gt;Click on &lt;em&gt;Create&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsri6xjl78zlwu9fckmqk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsri6xjl78zlwu9fckmqk.png" alt="Step 1 image" width="409" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The custom widget editor window will appear. A custom widget is composed of six different sections: &lt;strong&gt;Description&lt;/strong&gt;, &lt;strong&gt;Template&lt;/strong&gt;, &lt;strong&gt;Controller&lt;/strong&gt;, &lt;strong&gt;Assets&lt;/strong&gt;, &lt;strong&gt;Required angular modules&lt;/strong&gt;, and &lt;strong&gt;Properties&lt;/strong&gt;. As we are creating a custom widget, we will make some modifications in the &lt;strong&gt;Template&lt;/strong&gt;, &lt;strong&gt;Assets&lt;/strong&gt;, and &lt;strong&gt;Properties&lt;/strong&gt; sections.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5f1rf1zp0sit2l8hvop3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5f1rf1zp0sit2l8hvop3.png" alt="Step 1.1 image" width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Remove everything from all the sections. We are going to create our widget from scratch.&lt;/li&gt;
&lt;li&gt;Now, our widget editor window looks like this:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiu47n1w1oo59nfq99rxw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiu47n1w1oo59nfq99rxw.png" alt="Step 2 image" width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Define the Properties section
&lt;/h4&gt;

&lt;h4&gt;
  
  
  Step 3: Property 1: Value
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Click on the &lt;em&gt;Create&lt;/em&gt; button.&lt;/li&gt;
&lt;li&gt;A "Create new property" dialog box will appear.&lt;/li&gt;
&lt;li&gt;Set the properties:

&lt;ul&gt;
&lt;li&gt;Name = value&lt;/li&gt;
&lt;li&gt;Label = Value&lt;/li&gt;
&lt;li&gt;Treat value as = Bidirectional bond&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Click on &lt;em&gt;Create&lt;/em&gt;.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The value property saves the value we type in our widget.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft4ul84e546iwetl95nxj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft4ul84e546iwetl95nxj.png" alt="Step 3 image" width="609" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 4: Property 2: Placeholder
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Click on the &lt;em&gt;Create&lt;/em&gt; button.&lt;/li&gt;
&lt;li&gt;A "Create new property" dialog box will appear.&lt;/li&gt;
&lt;li&gt;Set the properties:

&lt;ul&gt;
&lt;li&gt;Name = placeholder&lt;/li&gt;
&lt;li&gt;Label = Placeholder&lt;/li&gt;
&lt;li&gt;Treat value as = Interpolation&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Click on &lt;em&gt;Create&lt;/em&gt;.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This property sets a custom placeholder for our widget.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1dhu4wmsa9qemj4t9qr2.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1dhu4wmsa9qemj4t9qr2.PNG" alt="Step 4 image" width="606" height="673"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  The Template section
&lt;/h4&gt;

&lt;p&gt;In the template section, we will write some internal CSS as well as HTML codes, which means the code applies to change the look and feel of a widget that appears on the whiteboard.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 5
&lt;/h4&gt;

&lt;p&gt;In the template section, write the following HTML and internal CSS codes:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;HTML&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div ng-if="environment"&amp;gt;
    &amp;lt;input class="search-input" /&amp;gt;
    &amp;lt;span class="icon-container"&amp;gt;&amp;lt;i class="glyphicon glyphicon-search"&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; in the HTML code above, &lt;code&gt;ng-if="environment"&lt;/code&gt; detects that the widget is displayed within the UI Designer whiteboard. It allows us to define how the widget is displayed to the developer within the UI Designer (as opposed to now the widget displayed to the user within a web page at runtime).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;CSS&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;style&amp;gt;
.search-input {
    padding: 0 15px;
    height: 35px;
    border: 1px solid rgba(11,67,97,1);
    border-radius: 35px;
    outline: none;
    color: rgba(11,67,97,1);
    width: 100%;
    opacity: 1;
    background: #fff;
}

.icon-container {
    position: absolute;
    right: 17px;
    padding: 9px;
    height: 35px;
    width: 35px;
    border: 1px solid rgba(11,67,97,1);
    border-radius: 50%;
    z-index: 5;
    background: rgba(11,67,97,1);
}

.icon-container .glyphicon {
    font-size: 16px;
    color: #fff;
}
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; All the CSS codes must be written inside the  tag. Since Bootstrap is embedded by default in the UI Designer, we can easily use the bootstrap glyphicons.&lt;/p&gt;

&lt;p&gt;Now, the widget editor looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fp0mrsi99cy9im2q1ay1p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fp0mrsi99cy9im2q1ay1p.png" alt="Step 5 image" width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on the Save button.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bravo!!!&lt;/strong&gt; We have created our search widget successfully.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 6 (optional)
&lt;/h4&gt;

&lt;h4&gt;
  
  
  Pro tip - Defining the widget icon
&lt;/h4&gt;

&lt;p&gt;Since Bonita will ultimately provide an easy way for Bonitasoft users to define the widget icon as per their need, &lt;strong&gt;Step 6 is not mandatory&lt;/strong&gt;. Nevertheless, to give a real look and feel to the custom search widget icon, you can try this pro tip:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the “customSearchWidget.json” file located inside your Bonita workspace (eg. /workspace/My project/web_widgets/customSearchWidget/customSearchWidget.json).&lt;/li&gt;
&lt;li&gt;Copy and paste the given code below after the “template” line inside the “customSearchWidget.json”.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"icon" : "&amp;lt;svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' fill='#fff'&amp;gt;&amp;lt;g transform='translate(0.000000,512.000000) scale(0.100000,-0.100000)' fill='#fff' stroke='none'&amp;gt;&amp;lt;path d='M1905 4794 c-512 -79 -967 -381 -1234 -817 -297 -485 -342 -1053 -124 -1570 160 -381 476 -715 848 -897 485 -237 1024 -237 1510 0 55 27 134 72 177 100 42 27 80 512 85 50 4 0 310 -301 678 -670 l670 -670 142 142 143 143 -667 667 c-665 665 -666 666 -650 690 9 13 48 66 87 118 124 169 241 432 284 641 79 384 26 776 -153 1127 -261 512 -751 865 -1312 947 -130 18 -361 18 -484 -1z m403 -195 c349 -38 647 -171 895 -399 390 -360 562 -928 445 -1469 -119 -555 -550 -1003 -1095 -1142 -169 -43 -265 -52 -463 -46 -307 10 -554 88 -801 252 -459 306 -709 829 -667 1399 58 801 700 1401 1511 1415 43 0 121 -4 175 -10z'/&amp;gt; &amp;lt;/g&amp;gt; &amp;lt;/svg&amp;gt;",
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwh81gq2oz0tthw661aij.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwh81gq2oz0tthw661aij.png" alt="Step 6 image" width="800" height="84"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The SVG code generates a magnifying glass icon for our search widget.&lt;/li&gt;
&lt;li&gt;Save the file and close it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hurray!!!!!!!!&lt;/strong&gt; We have now successfully changed an icon of the widget. Now, it's time to use our custom widget inside an application page.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 7
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Go to the Bonita UI Designer home page.&lt;/li&gt;
&lt;li&gt;Click on the &lt;em&gt;Create&lt;/em&gt; button.&lt;/li&gt;
&lt;li&gt;Choose &lt;em&gt;Application&lt;/em&gt; page.&lt;/li&gt;
&lt;li&gt;Give a name to the page (eg. searchApplication).&lt;/li&gt;
&lt;li&gt;Click on &lt;em&gt;Create&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Now, in the page editor window, click on the &lt;em&gt;Custom widgets&lt;/em&gt; tab on the left.&lt;/li&gt;
&lt;li&gt;We can see now that the searchWidget appears on the list and has a magnifying glass as an icon.&lt;/li&gt;
&lt;li&gt;Drag and drop the search widget onto the whiteboard.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Output
&lt;/h4&gt;

&lt;p&gt;The widget on the whiteboard will be shown the same as in the image below;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzjtlr63kl5rwapgl5zma.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzjtlr63kl5rwapgl5zma.PNG" alt="Step 7 image" width="800" height="133"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have completed the definition of the custom search widget, and now we are going to make the search widget functional to end-users.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4878twzoy8qsqotyznys.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4878twzoy8qsqotyznys.gif" alt="Minnions image" width="320" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The implementation steps that follow are based on a large device screen resolution (i.e., screen width &amp;gt;= 1200px). You can change the responsiveness of the page by clicking on the different device screen size icon that appears on the top right corner in Bonita UI Designer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Part II: Implement the custom search widget controller
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Step 8
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Click and select the custom search widget on the whiteboard.&lt;/li&gt;
&lt;li&gt;Click on the &lt;strong&gt;“...”&lt;/strong&gt; button next to the widget name on the right.&lt;/li&gt;
&lt;li&gt;Click on &lt;em&gt;Edit&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6u05kxsy1orh9k9rez5u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6u05kxsy1orh9k9rez5u.png" alt="Step 8 image" width="800" height="94"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The widget editor window will appear.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 9
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;In the Template section after the end of &lt;code&gt;&amp;lt;div ng-if="environment"&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; tag, write the following HTML code:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;HTML&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div ng-if="!environment" class="search-input-container"&amp;gt;
    &amp;lt;input 
        type= " text "
        ng-model= " properties.value "
        placeholder= " {{properties.placeholder | uiTranslate}} "
        onfocus= " this.value= '' " 
    /&amp;gt;
    &amp;lt;div class="search-icon"&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
```


**Note:** In the HTML code above, `ng-if="!environment"` detects that the widget displayed to the user within a web page at runtime. Additionally, `ng-modal="properties.value"` stores the value entered in the widget, and `placeholder="{{properties.placeholder}}"` defines the placeholder for the widget.

- Now the Template section looks like this:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/e5k6vjvao52a70xi9iuj.png)

#### Step 10 ####
- Create a CSS file somewhere on your computer (e.g., D:\search-wideget.css) and copy the following CSS code into it:

*CSS*


```
.search-input-container {
    width: 100%;
    height: auto;
}

.search-input-container .search-icon {
    position: absolute;
    top: 30px;
    right: 0;
    bottom: 0;
    left: 0;
    margin: auto;
    width: 35px;
    height: 35px;
    background: rgba(11,67,97,1);
    border-radius: 50%;
    transition: all 1s;
    z-index: 5;
    box-shadow: 0 0 15px 0 rgba(0,0,0,0.4);
}

.search-input-container .search-icon:hover {
    cursor: pointer;
}

.search-input-container .search-icon::before {
    content: "";
    position: absolute;
    margin: auto;
    width: 8px;
    height: 3px;
    background: #fff;
    top: 12px;
    right: 0;
    bottom: 0;
    left: 12px;
    transform: rotate(45deg);
    transition: all .5s;
}

.search-input-container .search-icon::after {
    content: "";
    position: absolute;
    margin: auto;
    height: 15px;
    width: 15px;
    border: 2px solid #fff;
    border-radius: 50%;
    top: -5px;
    right: 0;
    bottom: 0;
    left: -5px;
    transition: all .5s
}

.search-input-container input {
    position: absolute;
    margin: auto;
    padding: 0 60px 0 15px;
    width: 35px;
    height: 35px;
    top: 30px;
    right: 0;
    bottom: 0;
    left: 0;
    border: 1px solid rgba(11,67,97,1);
    border-radius: 35px;
    background: #fff;
    outline: none;
    color: rgba(11,67,97,1);
    z-index: 6;
    opacity: 0;
    transition: all 1s;
}

.search-input-container input:hover {
    cursor: pointer;
}

.search-input-container input:focus {
    width: 90%;
    opacity: 1;
    cursor: text;
}

.search-input-container input:focus ~ .search-icon {
    right: calc(-90% + 35px);
    background: rgba(11,67,97,1);
    z-index: 6;
}

.search-input-container input:focus ~ .search-icon::before {
    width: 15px;
    top: 0;
    left: 0;
}

.search-input-container input:focus ~ .search-icon::after {
    height: 3px;
    width: 15px;
    border: none;
    border-radius: 0;
    transform: rotate(-45deg);
    background: #fff;
    top: 0;
    right: 0;
    left: 0;
}
```


**Note:** You can define the vertical and horizontal positioning properties such as; top, bottom, left, and right as you wish. In the CSS code above, `“.search-input-container .search-icon::before”` and `“.search-input-container .search-icon::after”` creates a magnifying glass icon. Similarly, `“.search-input-container input:focus ~ .search-icon::before”` and `“.search-input-container input:focus ~ .search-icon::after”` creates an “X” icon. 

- Now, save the CSS file and close it.

#### Step 11 ####
- In the widget editor window in the Bonita UI Designer, click on the *Add* button in the **Assets** section and upload the CSS file we created in the previous step.

![Step 11 image](https://dev-to-uploads.s3.amazonaws.com/i/qvqe8umk990soweiqonp.png)
- After uploading the CSS file, the Assets section should show the file in the list as shown below:

![Step 11-2 image](https://dev-to-uploads.s3.amazonaws.com/i/yf43d7zqsppqkiextlja.png)

- Click on the *Save* button to save all the modifications applied to the widget.

#### Step 12 ####
- Go back to the Bonita UI Designer home page.
- Click on *searchApplication* (the page we created in part 1).

![Step 12 image](https://dev-to-uploads.s3.amazonaws.com/i/x9gfugdsuts52deffdhv.png)
- Clean the page if there is already a widget on it.

#### Step 13 ####
- Drag and drop a title widget to the whiteboard and set the properties:
 - Width = 12
 - Text = Custom Search Widget
 - Title level = Level 3
 - Alignment = center

![Step 13 image](https://dev-to-uploads.s3.amazonaws.com/i/xmy4d41n55yig0dno2ln.png)

#### Step 14 ####
- Drag and drop a container widget below the title and set the width property = 4.

![Step 14 image](https://dev-to-uploads.s3.amazonaws.com/i/d9bdippdo2whkcs1qj7h.png)

#### Step 15 ####
- Click on the *Custom widget* tab on the left.
- Drag and drop the searchWidget next to the empty container and set the properties:
 - Width = 4
 - Placeholder = Search text goes here...

![Step 15 image](https://dev-to-uploads.s3.amazonaws.com/i/hyha7u0jneog9l3yq86q.png)

#### Step 16 ####
- Drag and drop another container widget right to the search widget and set the width = 4.
- Finally, save the page and see the preview.

![Step 16 image](https://dev-to-uploads.s3.amazonaws.com/i/obuos7ikrz6t047cxr8u.png)

#### Output ####
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/2ntfuzzkgeb44b8q2x0q.gif)

![Minnions with a girl image](https://dev-to-uploads.s3.amazonaws.com/i/tpmt80r0dhbljci9jatc.gif)

I would love to know what other kinds of custom widgets you would like to implement with Bonita UI Designer. Please share your tips and examples.

Have fun with **Bonita!**


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>bonitasoft</category>
      <category>uidesigner</category>
      <category>customwidget</category>
    </item>
    <item>
      <title>Build Your First Custom Widget in Bonita UI Designer</title>
      <dc:creator>Bishal Thapaliya</dc:creator>
      <pubDate>Wed, 30 Sep 2020 13:24:45 +0000</pubDate>
      <link>https://forem.com/vishalthapaliya/build-your-first-custom-widget-in-bonita-ui-designer-4eg7</link>
      <guid>https://forem.com/vishalthapaliya/build-your-first-custom-widget-in-bonita-ui-designer-4eg7</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj4ptgm514sa6kvy7czh0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj4ptgm514sa6kvy7czh0.png" alt="Cover image" width="603" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A web developer always wants to have just the right widget handy - and sometimes they have to create their own when they can’t find just the right one among the widgets provided. This article is to help new Bonita users especially, but is for anyone who wants to learn how to create a custom widget in Bonita UI Designer. In this article, I am going to explain how to create a custom &lt;em&gt;Hello World!&lt;/em&gt; widget to use on our application page.&lt;/p&gt;

&lt;h4&gt;
  
  
  Prerequisite
&lt;/h4&gt;

&lt;p&gt;Bonita Studio must be installed on your computer to launch the Bonita UI Designer. You can download Bonita Studio from &lt;a href="https://www.bonitasoft.com/downloads" rel="noopener noreferrer"&gt;here.&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;In the Bonita UI Designer home page, click on the &lt;em&gt;Create&lt;/em&gt; button.&lt;/li&gt;
&lt;li&gt;Choose Custom widget in the &lt;strong&gt;Type&lt;/strong&gt; section.&lt;/li&gt;
&lt;li&gt;Define a name for the widget (eg. HelloWorldWidget).&lt;/li&gt;
&lt;li&gt;Click on &lt;em&gt;Create&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;The editor window for the widget “HelloWorldWidget” will appear.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbjp4cqtpcleoq422m5hn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbjp4cqtpcleoq422m5hn.png" alt="Step 1 image" width="800" height="458"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;A custom widget is composed of six different sections: &lt;strong&gt;Description&lt;/strong&gt;, &lt;strong&gt;Template&lt;/strong&gt;, &lt;strong&gt;Controller&lt;/strong&gt;, &lt;strong&gt;Assets&lt;/strong&gt;, &lt;strong&gt;Required angular modules&lt;/strong&gt;, and &lt;strong&gt;Properties&lt;/strong&gt;. Since we are creating a simple custom widget to display a “Hello World!” text, we will make some modifications in the &lt;strong&gt;Template&lt;/strong&gt; section only.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: Edit
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;First, remove everything from all the sections. &lt;/li&gt;
&lt;li&gt;Now, our widget editor window looks like this:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fd9sirm1q8amn4sbe9frs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fd9sirm1q8amn4sbe9frs.png" alt="Step 2 image" width="800" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3: Create a template for the widget
&lt;/h4&gt;

&lt;p&gt;In the template section, we write the HTML for the widget we want to build and it will be shown to the end-users when we see the preview.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the template section, write the following HTML code;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;HTML&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Hello World!&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; tag creates a second-level heading in the HTML document.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fym8ir686cp4vqej9o4ea.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fym8ir686cp4vqej9o4ea.png" alt="Step 3 image" width="800" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on the &lt;em&gt;Save&lt;/em&gt; button.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 4: Use the HelloWorldWidget into an application page
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;In the Bonita UI Designer homepage, click on the &lt;em&gt;Create&lt;/em&gt; button.&lt;/li&gt;
&lt;li&gt;Choose the Application page in the &lt;strong&gt;Type&lt;/strong&gt; section.&lt;/li&gt;
&lt;li&gt;Define a name for the page (eg. HelloWorld).&lt;/li&gt;
&lt;li&gt;Click on &lt;em&gt;Create&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;A page editor window will open.&lt;/li&gt;
&lt;li&gt;Click on the custom widgets tab on the left.&lt;/li&gt;
&lt;li&gt;We can see now that HelloWorldWidget appears in the list.&lt;/li&gt;
&lt;li&gt;Now, drag and drop the HelloWorld widget onto the whiteboard.&lt;/li&gt;
&lt;li&gt;Set the width property to 12 columns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Floomdmq6lwi2nipsweml.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Floomdmq6lwi2nipsweml.png" alt="Alt Text" width="800" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on the &lt;em&gt;Save&lt;/em&gt; button.&lt;/li&gt;
&lt;li&gt;Click on the &lt;em&gt;Preview&lt;/em&gt; button to see the output.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Output
&lt;/h4&gt;

&lt;p&gt;We can now see &lt;em&gt;Hello World!&lt;/em&gt; with a second-level heading format in the preview.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj4ptgm514sa6kvy7czh0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj4ptgm514sa6kvy7czh0.png" alt="Cover image" width="603" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that you can create a simple custom Hello World! widget easily. In my other article, I have explained how to create a custom search widget, how to change the look and feel of a custom widget that appears on the whiteboard, and a pro tip on how to change the custom widget icon when it appears on the list. The custom search widget will be the same as shown in the image below. Click &lt;a href="https://dev.to/vishalthapaliya/build-a-custom-search-widget-in-bonita-ui-designer-4m0j"&gt;here&lt;/a&gt; to learn about building a custom search widget in Bonita UI Designer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8xq8nkjl7scwrct190cx.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8xq8nkjl7scwrct190cx.gif" alt="Alt Text" width="450" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stay tuned. Have fun with Bonita!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>HOW TO CREATE A TYPING ANIMATION WITH CSS IN BONITA UI DESIGNER</title>
      <dc:creator>Bishal Thapaliya</dc:creator>
      <pubDate>Mon, 27 Jul 2020 17:37:32 +0000</pubDate>
      <link>https://forem.com/vishalthapaliya/how-to-create-a-typing-animation-with-css-in-bonita-ui-designer-2ld5</link>
      <guid>https://forem.com/vishalthapaliya/how-to-create-a-typing-animation-with-css-in-bonita-ui-designer-2ld5</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvi2iv19a599qbovkk7vu.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvi2iv19a599qbovkk7vu.gif" alt="cover image" width="600" height="337"&gt;&lt;/a&gt;&lt;br&gt;
CSS allows us to add animation without using JavaScript to the HTML elements to change incrementally from one style to another as many times as we want. To add an animation to the elements, we need to specify the @keyframes. In this post, I will explain how to add a typing animation effect to the text-widget in Bonita UI Designer using CSS. (If you are using something other than the Bonita UI Designer for your interface design, you may write your own HTML and define the CSS classes for all the elements so that you can use the same CSS codes for this effect.)&lt;/p&gt;

&lt;h5&gt;
  
  
  Step 1
&lt;/h5&gt;

&lt;p&gt;First, create a new application page in Bonita UI Designer.&lt;/p&gt;

&lt;h5&gt;
  
  
  Step 2
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fihdykw9b7efca3a6gv2b.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fihdykw9b7efca3a6gv2b.PNG" alt="step 2 image" width="800" height="148"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drag and drop a container widget in the blank area on the page.&lt;/li&gt;
&lt;li&gt;Set the properties:

&lt;ul&gt;
&lt;li&gt;Width = 12&lt;/li&gt;
&lt;li&gt;CSS classes = main-container&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Open style.css and write the following code and save it:
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.main-container {
    display: inline-block;
    background-image: url('../img/background.png');
    background-size: cover;
    height: 100vh;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note:&lt;/em&gt;&lt;/strong&gt; for the background image, I have added an image file as an asset called "background.png". You can add a background image as per your requirement.&lt;/p&gt;

&lt;h5&gt;
  
  
  Step 3
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4n9gcr3jrpngvaj69uyy.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4n9gcr3jrpngvaj69uyy.PNG" alt="step 3 image" width="800" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drag and drop a title widget inside the “main-container”.&lt;/li&gt;
&lt;li&gt;Set the properties:

&lt;ul&gt;
&lt;li&gt;Width = 12&lt;/li&gt;
&lt;li&gt;Text = Digital process automation for a competitive edge&lt;/li&gt;
&lt;li&gt;Title level = Level 1&lt;/li&gt;
&lt;li&gt;Alignment = left&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Open style.css and write the following code and save it:
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.main-container h1 {
    display: inline-block;
    margin-top: 15%;
    margin-left: 5%;
    font-size: 3vw;
    color: #cdd026;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: you can change the CSS properties as per your background image.&lt;/p&gt;

&lt;h5&gt;
  
  
  Step 4
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvwj4ubu3kv1ltijlu8lw.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvwj4ubu3kv1ltijlu8lw.PNG" alt="step 4 image" width="800" height="125"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drag and drop a container widget below the title widget inside the “main-container”.&lt;/li&gt;
&lt;li&gt;Set the properties:

&lt;ul&gt;
&lt;li&gt;Width = 12&lt;/li&gt;
&lt;li&gt;CSS = typing-text-container&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Open style.css and write the following code and save it:
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.typing-text-container {
    width: 650px;
    margin-left: 5%;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Step 5
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyg7q11k0aus8qo2lwh33.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyg7q11k0aus8qo2lwh33.PNG" alt="step 5 image" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drag and drop a text widget inside the “typing-text-container”.&lt;/li&gt;
&lt;li&gt;Set the properties:

&lt;ul&gt;
&lt;li&gt;Width = 12&lt;/li&gt;
&lt;li&gt;CSS = typing-text&lt;/li&gt;
&lt;li&gt;Text = Re-invent your business processes with Bonita platform&lt;/li&gt;
&lt;li&gt;Alignment = left&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Open style.css and write the following code and save it:
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.typing-text p{
    border-right: 2px solid #337ab7;
    font-size: 170%;
    white-space: nowrap;
    overflow: hidden;
    animation: typewriter 10s steps(54) forwards,
                blinkingCursor .8s step-end infinite ;
    animation-iteration-count: infinite;
    color: #fff;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: In the CSS, we need to define the properties for animation such as name, duration, delay, direction, iteration-count, etc. Similarly, the value 54 for steps in the animation property defines up to the number of characters (including white spaces) we want to add to an animation.&lt;/p&gt;

&lt;h5&gt;
  
  
  Step 6
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Now we need to specify the keyframes for the animations such as typewriter and blinkingCursor.&lt;/li&gt;
&lt;li&gt;Open style.css and write the following code and save it:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@keyframes typewriter {
        0% {width: 0;}
        30% {width: 95%;}
        80% {width: 95%;}
        90% {width: 0;}
        100% {width: 0;}
 }

@keyframes blinkingCursor {
        from, to {
                border-right-color: transparent;
        }
        50% {
                border-right-color: #337ab7;
        }
        to {
                border-right-color: transparent;
        }
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Output
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Now, save the page and when we click on the preview we will see an output as shown in the picture below.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvi2iv19a599qbovkk7vu.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvi2iv19a599qbovkk7vu.gif" alt="output image" width="600" height="337"&gt;&lt;/a&gt;&lt;br&gt;
You can change the font color for the title and the text widgets to make it more readable against the background image.&lt;/p&gt;

&lt;p&gt;I would love to know what other CSS animation effects you would like to implement with Bonita UI Designer. Please share your tips and examples.&lt;/p&gt;

&lt;p&gt;Have fun with Bonita!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to create a circle clip-path hover effect in Bonita UI Designer</title>
      <dc:creator>Bishal Thapaliya</dc:creator>
      <pubDate>Tue, 21 Jul 2020 13:57:58 +0000</pubDate>
      <link>https://forem.com/vishalthapaliya/how-to-create-a-circle-clip-path-hover-effect-in-bonita-ui-designer-1fn1</link>
      <guid>https://forem.com/vishalthapaliya/how-to-create-a-circle-clip-path-hover-effect-in-bonita-ui-designer-1fn1</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F09bq1tyauo20zj4nrshm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F09bq1tyauo20zj4nrshm.gif" alt="banner image" width="760" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The CSS clip-path property allows us to set the area of an element we want to display. This cool property is very handy to create complex shapes in CSS, such as a circle, polygon, ellipse, star, pentagon, hexagon - and many more. In this post, I am going to show you how to create a cool circle clip-path effect on a mouse hover using &lt;strong&gt;Bonita UI Designer&lt;/strong&gt;. Although this step by step is specific to the &lt;strong&gt;Bonita UI Designer&lt;/strong&gt;, you can use the CSS for this effect in any user interface designer. (If you are using something other than the &lt;strong&gt;Bonita UI Designer&lt;/strong&gt; for your interface design, you may write your own HTML and define the CSS classes for all the elements so that you can use the same CSS codes for this effect.)&lt;/p&gt;

&lt;h4&gt;
  
  
  Steps to follow
&lt;/h4&gt;

&lt;p&gt;First of all, create a new application page in Bonita UI Designer.&lt;/p&gt;

&lt;h5&gt;
  
  
  Step 1
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8926dnrlya3owlqh05s0.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8926dnrlya3owlqh05s0.PNG" alt="Step 1 image" width="800" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drag and drop a container widget into the blank area on the page.&lt;/li&gt;
&lt;li&gt;Set these properties:

&lt;ul&gt;
&lt;li&gt;Width = 3&lt;/li&gt;
&lt;li&gt;CSS classes = card-container&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Go to Assets &amp;gt; style.css (Click on the pencil icon to edit CSS) &lt;/li&gt;

&lt;li&gt;Write the following code and save it.
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.card-container {
    position: relative;
    width: 280px;
    height: 380px;
    margin: 20px 15px;
    box-sizing: border-box;
    overflow: hidden;
    } 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Step 2
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Figeeey7uslwusrsh8i7z.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Figeeey7uslwusrsh8i7z.PNG" alt="Step 2 image" width="800" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drag and drop another container widget inside the “card-container”.&lt;/li&gt;
&lt;li&gt;Set the properties:

&lt;ul&gt;
&lt;li&gt;Width = 12&lt;/li&gt;
&lt;li&gt;CSS classes = image-container&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Open style.css and write the following code:
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.image-container {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    clip-path: circle(380px at center 100px);
    -webkit-clip-path: circle(380px at center 100px);
    transition: 0.6s;
    transition-delay: 0.6s;
    padding: 0;
}
.card-container:hover .image-container {
    clip-path: circle(90px at center 100px);
    -webkit-clip-path: circle(90px at center 100px); 
    transition-delay: 0s;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Step 3
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flyl2x3d16kcaqjnyyyx6.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flyl2x3d16kcaqjnyyyx6.PNG" alt="Step 3 image" width="800" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to Assets and add all the images you want to use on this page. Here, I am using some superhero images as examples and if you would like to use the same images, get it from &lt;a href="https://drive.google.com/drive/folders/1EVp7rcLT2mDSGFDFAC-TLf6htSbrZ4zz?usp=sharing" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Now, drag and drop the image widget inside the “image-container”.&lt;/li&gt;
&lt;li&gt;Set the properties as given below;

&lt;ul&gt;
&lt;li&gt;Width = 12&lt;/li&gt;
&lt;li&gt;Source Type = Asset&lt;/li&gt;
&lt;li&gt;Asset Name = captain.jpg (asset name is an image file name which we added as an asset).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Open style.css and write the following code:
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.image-container img {
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Step 4
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiv264f7uaxg3h03pft44.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiv264f7uaxg3h03pft44.PNG" alt="Step 4 image" width="800" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drag and drop another container widget just below the “image-container” inside “card-container”.&lt;/li&gt;
&lt;li&gt;Set the properties:

&lt;ul&gt;
&lt;li&gt;Width = 12&lt;/li&gt;
&lt;li&gt;CSS classes = card-content&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Open style.css and write the following code:
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.card-content {
    position: absolute; 
    left: 0;
    bottom: 0;
    width: 100%;
    height: 55%;
    padding: 30px;
    box-sizing: border-box;
    text-align: center;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Step 5
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2h7jauo6haqrg7bg254b.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2h7jauo6haqrg7bg254b.PNG" alt="Step 5 image" width="800" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drag and drop a title widget inside the “card-content”.&lt;/li&gt;
&lt;li&gt;Set the properties:

&lt;ul&gt;
&lt;li&gt;Width = 12&lt;/li&gt;
&lt;li&gt;Text = Captain America&lt;/li&gt;
&lt;li&gt;Title level = Level 3&lt;/li&gt;
&lt;li&gt;Alignment = center&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h5&gt;
  
  
  Step 6
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5ehe60wq56awvroupreb.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5ehe60wq56awvroupreb.PNG" alt="Step 6 image" width="800" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drag and drop a text widget inside the “card-content”.&lt;/li&gt;
&lt;li&gt;Set the properties:

&lt;ul&gt;
&lt;li&gt;Width = 12&lt;/li&gt;
&lt;li&gt;CSS classes = description&lt;/li&gt;
&lt;li&gt;Text = Captain America is an American superhero film based on the Marvel Comics character.
Alignment = center&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Open style.css and write the following code:
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.card-content .description {
    overflow: hidden;
    text-overflow: ellipsis;
    height: 55px;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Step 7
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flm6jkshica05g7l3ziiu.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flm6jkshica05g7l3ziiu.PNG" alt="Step 7 image" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drag and drop a Link widget just below the Text widget (description) inside “card-content”.&lt;/li&gt;
&lt;li&gt;Set the properties:

&lt;ul&gt;
&lt;li&gt;Width = 12&lt;/li&gt;
&lt;li&gt;Text = Read more&lt;/li&gt;
&lt;li&gt;Alignment = center&lt;/li&gt;
&lt;li&gt;Style = primary&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Open style.css and write the following code:
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.card-content h3,
.card-content .description,
.card-content a {
    opacity: 0;
    transition: 0.5s;
    transform: translateY(20px);
}
.card-container:hover .card-content h3 {
    opacity: 1;
    transform: translateY(0);
    transition-delay: 0.5s;
    margin: auto;
}
.card-container:hover .card-content .description {
    opacity: 1;
    transform: translateY(0);
    transition-delay: 0.7s
}
.card-container:hover .card-content a {
    opacity: 1;
    transform: translateY(0);
    transition-delay: 0.9s
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Output
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F09bq1tyauo20zj4nrshm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F09bq1tyauo20zj4nrshm.gif" alt="output image" width="760" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, you can repeat the steps above to create more and more cards as per your requirement.&lt;/p&gt;

&lt;p&gt;I would love to know what other CSS clip-path examples you would like to implement with Bonita UI Designer. Please share your tips and examples.&lt;/p&gt;

&lt;p&gt;Have fun with Bonita!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>12 simple steps to build a neumorphic login page with Bonita UI Designer</title>
      <dc:creator>Bishal Thapaliya</dc:creator>
      <pubDate>Fri, 22 May 2020 14:20:14 +0000</pubDate>
      <link>https://forem.com/vishalthapaliya/12-simple-steps-to-build-a-neumorphic-login-page-with-bonita-ui-designer-27nh</link>
      <guid>https://forem.com/vishalthapaliya/12-simple-steps-to-build-a-neumorphic-login-page-with-bonita-ui-designer-27nh</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm23acifnivmxw6bueqb4.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm23acifnivmxw6bueqb4.PNG" alt="Cover image" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The interface style known as neumorphic (a combination of skeumorphic and realistic design) has been gaining in popularity, and I think we'll see it being used more and more in 2020.&lt;/p&gt;

&lt;p&gt;One important aspect of neumorphism is about selecting the proper color palettes, and 3 shades of the same color are required for this.&lt;/p&gt;

&lt;p&gt;i) Light Shadow should be done by using a light color. For example, rgba(255,255,255,1),&lt;/p&gt;

&lt;p&gt;ii) The Main background and Element color should be in the mid-range. For example, rgba(235,245,252,1) for the background and element,&lt;/p&gt;

&lt;p&gt;iii) Dark Shadow should be done by using a dark color. For instance, rgba(0,0,0,0.1).&lt;/p&gt;

&lt;p&gt;Below are the 12 simple steps I followed to implement a login page using the Bonita UI Designer, inspired by &lt;a href="https://neumorphism.io/" rel="noopener noreferrer"&gt;https://neumorphism.io/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, create a new application page in UI Designer.&lt;/p&gt;

&lt;p&gt;Step: 1&lt;br&gt;
In the UI Designer whiteboard, drag &amp;amp; drop a container widget, give the CSS class name as “logo-box”  and set the column width to 6. We will put our company logo in this container.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvm2ija3vrm353h9z81fc.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvm2ija3vrm353h9z81fc.PNG" alt="Step 1 image" width="800" height="137"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step: 2&lt;br&gt;
Inside the logo-box, place the logo and title as you want. Here I am using an image widget for the logo and a text widget for the company’s name. I have added the Bonitasoft logo in UI Designer as an image asset.&lt;/p&gt;

&lt;p&gt;Now, set the properties as given below for the image widget:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Width = 12;
&lt;/li&gt;
&lt;li&gt;Source Type  = Asset; &lt;/li&gt;
&lt;li&gt;Asset Name = bonitasoftLogo.png&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can download the Bonitasoft logo from this &lt;a href="https://drive.google.com/open?id=1rGZpdzD7XycsgjYFAN7BO2qkKxzQgiaV" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1d75of8l64b42kz86jeu.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1d75of8l64b42kz86jeu.PNG" alt="Step 2 logo image" width="800" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Set the properties as given below for the text widget:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Width = 12;
&lt;/li&gt;
&lt;li&gt;CSS classes = bonita; &lt;/li&gt;
&lt;li&gt;Text =

&lt;code&gt;Bonita&amp;lt;span class=”soft”&amp;gt;soft&amp;lt;/span&amp;gt;&lt;/code&gt;

;&lt;/li&gt;
&lt;li&gt;Alignment = center&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fijl50ue768ybkfmjkqyk.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fijl50ue768ybkfmjkqyk.PNG" alt="Step 2 text" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h5&gt;
  
  
  Note: Since the company logo and the title can be different, I suggest you write your own CSS for this part.
&lt;/h5&gt;

&lt;p&gt;Step: 3&lt;br&gt;
In the whiteboard outside the logo-box, drag &amp;amp; drop a form container widget next to the logo-box, give the CSS class name as “login-form” and set the column width to 6. We will use this form container to implement our login form.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fleuus5fqhwugv681dalb.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fleuus5fqhwugv681dalb.PNG" alt="Step 3 image" width="800" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step: 4&lt;br&gt;
Inside the login-form, create a title using title widget and set the properties as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Width = 12;   Text = Login;   Title level = Level 2;  Alignment = center&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4i92v9ufwki0wxethccf.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4i92v9ufwki0wxethccf.PNG" alt="Step 4 image" width="800" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step: 5&lt;br&gt;
Below the title, drag &amp;amp; drop a new container, give the CSS class name as “input-container” and set the column width to 12.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fas571rqvky9cj2gdykb4.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fas571rqvky9cj2gdykb4.PNG" alt="Step 5 image" width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step: 6&lt;br&gt;
Inside the input-container, drag &amp;amp; drop an input widget and set the properties as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Width = 12;   CSS classes = input-widget; Label = Username;&lt;/li&gt;
&lt;li&gt;Placeholder = &lt;a href="mailto:username@address.com"&gt;username@address.com&lt;/a&gt; (you can put whatever email address you want to);&lt;/li&gt;
&lt;li&gt;Type = Email&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw7ng9nuuj1ygj1iymbpd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw7ng9nuuj1ygj1iymbpd.png" alt="Step 6 image" width="800" height="1050"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step: 7&lt;br&gt;
Below the username, drag &amp;amp; drop another input widget and set the properties as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Width = 12;   CSS classes = input-widget; Label = Password&lt;/li&gt;
&lt;li&gt;Placeholder = ……… ; Type = Password&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fylz85usrua3ezpi7jv76.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fylz85usrua3ezpi7jv76.PNG" alt="Step 7 image" width="638" height="880"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step: 8&lt;br&gt;
Below the password widget, drag &amp;amp; drop a button widget and set the properties as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Width = 12;   CSS classes = input-widget; Label = Sign in;&lt;/li&gt;
&lt;li&gt;Alignment = center;&lt;/li&gt;
&lt;li&gt;Style = default;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Filtxce4011a06dd2j9kb.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Filtxce4011a06dd2j9kb.PNG" alt="Step 8 image" width="800" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step: 9&lt;br&gt;
Now, outside the input-container, drag &amp;amp; drop a container, give the CSS class name as “forget-password” and set the column width to 12.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1g8o8yz5f1h0r4inpasq.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1g8o8yz5f1h0r4inpasq.PNG" alt="Step 9 image" width="800" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step: 10&lt;br&gt;
Inside the forget-password container, drag &amp;amp; drop a text widget and set the properties as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Width = 6;    Text = Forgot password?;    Alignment = right&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fk9znzw56vl126hq808l8.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fk9znzw56vl126hq808l8.PNG" alt="Step 10 image" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step: 11&lt;br&gt;
Just to the right to the text widget, drag &amp;amp; drop a Link widget and set the properties as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Widget = 6;   Text = Click here;  Alignment = left;       Style = link&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv5meg02ts1tpyuc0e535.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv5meg02ts1tpyuc0e535.PNG" alt="Step 11 image" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step: 12&lt;br&gt;
Go to Assets &amp;gt; style.css and write the CSS below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.logo-box {
    height: 100vh;
    position: relative;
    text-align: center; 
    background: rgba(235,245,252,1);
} 
.logo-box img {
   width: 40%;
   margin: 0 auto;
   padding: 15% 0 0;
}
.bonita{
    font-size: 4em;
    color: #0A4561;
}
.bonita .soft {
    color: #B52A2A;
}
.login-form {
    height: 100vh;
    position: relative;
    padding: 40px 40px 60px;
    background: rgba(235,245,252,1);
    text-align: center;
}
.input-container {
    text-align: left;
    padding: 40px 40px 60px;
    margin-top: 40px;
    box-shadow: -5px -5px 10px  rgba(255,255,255,0.8),
                 5px 5px 15px rgba(0,0,0,0.1);
    border-radius: 10px;
}
.login-form h2 {
    color: #0A4561;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 6px;
}

.input-container .input-widget {
    margin-top: 20px;
}
.input-container .input-widget label {
    display: block;
    color: #868686;
    margin-bottom: 5px;
    font-size: 18px;
}
.input-container .input-widget input,
.input-container .input-widget button {
    width: 100%;
    height: 50px;
    background: rgba(235,245,252,1);
    border: none;
    outline: none;
    border-radius: 40px;
    padding: 5px 15px;
    font-size: 18px;
    color: #32a3b1;
    box-shadow: inset -2px -2px   6px rgba(255,255,255,1),
                inset 2px 2px 6px rgba(0,0,0,0.1);
}
.input-container .input-widget input::placeholder {
    color: #bdcada;
    font-size: 18px;
}

.input-container .input-widget button {
    margin-top: 20px;
    box-shadow: -2px -2px 6px rgba(255,255,255,1),
          2px 2px 6px rgba(0,0,0,0.1);
}
.input-container .input-widget button:active{
    color: #006c9c;
    margin-top: 20px;
    box-shadow: inset -2px -2px 6px rgba(255,255,255,1),
  inset 2px 2px 6px rgba(0,0,0,0.1);
    outline: none;
}
.forget-password .component {
    margin-top: 30px;
    padding-right: 0;
    color: #0A4561;
}
.forget-password a {
    padding: 0;
    color: #B52A2A;
    text-decoration: none;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, save the page and click on the preview. We will see a beautiful neumorphic login page as shown below;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkm0gtfzc6b16s2r5fxi5.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkm0gtfzc6b16s2r5fxi5.PNG" alt="Output image" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: For a responsive page, Bonita Subscription users can define the size of the elements based on different screen sizes by clicking screen size icons to the top-right corner in the UI Designer.&lt;/p&gt;

&lt;p&gt;Similarly, Bonita Community users can create a responsive login page by following the tutorial &lt;a href="https://documentation.bonitasoft.com/bonita/7.10/responsiveness-with-community-edition" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I would love to know if you are into neumorphism as well. What are the colors you use? Please share your tips and examples.&lt;/p&gt;

&lt;p&gt;And remember, have fun with Bonita!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
