diff --git a/BlazorBootstrap.Demo.RCL/Components/Layout/MainLayout.razor.cs b/BlazorBootstrap.Demo.RCL/Components/Layout/MainLayout.razor.cs
index 64f809290..d2f9c7d53 100644
--- a/BlazorBootstrap.Demo.RCL/Components/Layout/MainLayout.razor.cs
+++ b/BlazorBootstrap.Demo.RCL/Components/Layout/MainLayout.razor.cs
@@ -22,6 +22,7 @@ internal override IEnumerable<NavItem> GetNavItems()
             new (){ Id = "401", Text = "Currency Input", Href = RouteConstants.Demos_CurrencyInput_Documentation, IconName = IconName.CurrencyDollar, ParentId = "4" },
             new (){ Id = "402", Text = "Date Input", Href = RouteConstants.Demos_DateInput_Documentation, IconName = IconName.CalendarDate, ParentId = "4" },
             new (){ Id = "403", Text = "Number Input", Href = RouteConstants.Demos_NumberInput_Documentation, IconName = IconName.InputCursor, ParentId = "4" },
+            new (){ Id = "403", Text = "Password Input", Href = RouteConstants.Demos_PasswordInput_Documentation, IconName = IconName.EyeSlashFill, ParentId = "4" },
             new (){ Id = "403", Text = "Radio Input", Href = RouteConstants.Demos_RadioInput_Documentation, IconName = IconName.RecordCircle, ParentId = "4" },
             new (){ Id = "404", Text = "Range Input", Href = RouteConstants.Demos_RangeInput_Documentation, IconName = IconName.Sliders, ParentId = "4" },
             //new (){ Id = "404", Text = "Select Input", Href = RouteConstants.Demos_SelectInput_Documentation, IconName = IconName.MenuButtonWideFill, ParentId = "4" },
diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Form/PasswordInput/PasswordInputDocumentation.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Form/PasswordInput/PasswordInputDocumentation.razor
new file mode 100644
index 000000000..d8dcab10c
--- /dev/null
+++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Form/PasswordInput/PasswordInputDocumentation.razor
@@ -0,0 +1,51 @@
+@page "/password-input"
+
+@attribute [Route(pageUrl)]
+
+<PageMetaTags PageUrl="@pageUrl"
+              Title="@metaTitle"
+              Description="@metaDescription"
+              ImageUrl="@imageUrl" />
+
+<PageHero Heading="@pageTitle">
+    <LeadSection>@pageDescription</LeadSection>
+</PageHero>
+
+<CarbonAds />
+
+<Section Size="HeadingSize.H2" Name="Basic usage" PageUrl="@pageUrl" Link="basic-usage">
+    <Demo Type="typeof(PasswordInput_Demo_01_Basic_Usage)" Tabs="true" />
+</Section>
+
+<Section Size="HeadingSize.H2" Name="Disable" PageUrl="@pageUrl" Link="disable">
+    <div class="mb-3">Use the <code>Disabled</code> parameter to disable the <code>TextInput</code>.</div>
+    <Demo Type="typeof(PasswordInput_Demo_02_Disable_A)" Tabs="false" />
+    <div class="my-3">Also, use <b>Enable()</b> and <b>Disable()</b> methods to enable and disable the <code>TextInput</code>.</div>
+    <Callout Color="CalloutColor.Warning" Heading="NOTE">
+        Do not use both the <b>Disabled</b> parameter and <b>Enable()</b> &amp; <b>Disable()</b> methods.
+    </Callout>
+    <Demo Type="typeof(PasswordInput_Demo_02_Disable_B)" Tabs="false" />
+</Section>
+
+<Section Size="HeadingSize.H2" Name="Valdations" PageUrl="@pageUrl" Link="validations">
+    <div class="mb-3">
+        Like any other blazor input component, <code>PasswordInput</code> supports validations.
+        Add the DataAnnotations on the <code>PasswordInput</code> component to validate the user input before submitting the form.
+        In the below example, we used <b>Required</b> attribute.
+    </div>
+    <Demo Type="typeof(PasswordInput_Demo_03_Validations)" Tabs="true" />
+</Section>
+
+<Section Size="HeadingSize.H2" Name="Events: ValueChanged" PageUrl="@pageUrl" Link="events-value-changed">
+    <div class="mb-3">This event fires when the <code>PasswordInput</code> value changes, but not on every keystroke.</div>
+    <Demo Type="typeof(PasswordInput_Demo_04_Events_ValueChanged)" Tabs="true" />
+</Section>
+
+@code {
+    private const string pageUrl = RouteConstants.Demos_PasswordInput_Documentation;
+    private const string pageTitle = "Blazor PasswordInput";
+    private const string pageDescription = "The Blazor Bootstrap PasswordInput component is constructed using an HTML input of type 'password'.";
+    private const string metaTitle = "Blazor PasswordInput Component";
+    private const string metaDescription = "The Blazor Bootstrap PasswordInput component is constructed using an HTML input of type 'password'.";
+    private const string imageUrl = "https://i.imgur.com/1mVjqQv.png"; // TODO: Update image URL
+}
diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Form/PasswordInput/PasswordInput_Demo_01_Basic_Usage.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Form/PasswordInput/PasswordInput_Demo_01_Basic_Usage.razor
new file mode 100644
index 000000000..4b0c05b09
--- /dev/null
+++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Form/PasswordInput/PasswordInput_Demo_01_Basic_Usage.razor
@@ -0,0 +1,8 @@
+<div class="mb-3">
+    <PasswordInput @bind-Value="@enteredPassword" />
+</div>
+<div class="mb-3">Entered password: @enteredPassword</div>
+
+@code {
+    private string? enteredPassword = null;
+}
diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Form/PasswordInput/PasswordInput_Demo_02_Disable_A.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Form/PasswordInput/PasswordInput_Demo_02_Disable_A.razor
new file mode 100644
index 000000000..d47989563
--- /dev/null
+++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Form/PasswordInput/PasswordInput_Demo_02_Disable_A.razor
@@ -0,0 +1,20 @@
+<div class="mb-3">
+    <PasswordInput @bind-Value="@enteredPassword" Disabled="@disabled" />
+</div>
+<div class="mb-3">Entered password: @enteredPassword</div>
+
+<Button Color="ButtonColor.Primary" @onclick="Enable"> Enable </Button>
+<Button Color="ButtonColor.Secondary" @onclick="Disable"> Disable </Button>
+<Button Color="ButtonColor.Warning" @onclick="Toggle"> Toggle </Button>
+
+@code {
+    private string? enteredPassword = null;
+
+    private bool disabled = true;
+
+    private void Enable() => disabled = false;
+
+    private void Disable() => disabled = true;
+
+    private void Toggle() => disabled = !disabled;
+}
diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Form/PasswordInput/PasswordInput_Demo_02_Disable_B.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Form/PasswordInput/PasswordInput_Demo_02_Disable_B.razor
new file mode 100644
index 000000000..367c8bbc8
--- /dev/null
+++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Form/PasswordInput/PasswordInput_Demo_02_Disable_B.razor
@@ -0,0 +1,17 @@
+<div class="mb-3">
+    <PasswordInput @ref="passwordInputRef" @bind-Value="@enteredPassword" />
+</div>
+<div class="mb-3">Entered text: @enteredPassword</div>
+
+<Button Color="ButtonColor.Secondary" @onclick="Disable"> Disable </Button>
+<Button Color="ButtonColor.Primary" @onclick="Enable"> Enable </Button>
+
+@code {
+    private PasswordInput? passwordInputRef;
+
+    private string? enteredPassword = null;
+
+    private void Disable() => passwordInputRef.Disable();
+
+    private void Enable() => passwordInputRef.Enable();
+}
diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Form/PasswordInput/PasswordInput_Demo_03_Validations.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Form/PasswordInput/PasswordInput_Demo_03_Validations.razor
new file mode 100644
index 000000000..92dd7d08b
--- /dev/null
+++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Form/PasswordInput/PasswordInput_Demo_03_Validations.razor
@@ -0,0 +1,80 @@
+@using System.ComponentModel.DataAnnotations
+
+<style>
+    .valid.modified:not([type=checkbox]) {
+        outline: 1px solid #26b050;
+    }
+
+    .invalid {
+        outline: 1px solid red;
+    }
+
+    .validation-message {
+        color: red;
+    }
+</style>
+
+<EditForm EditContext="@editContext" OnValidSubmit="HandleOnValidSubmit">
+    <DataAnnotationsValidator />
+
+    <div class="form-group row mb-3">
+        <label class="col-md-2 col-form-label">User name: <span class="text-danger">*</span></label>
+        <div class="col-md-10">
+            <TextInput @bind-Value="@userLogin.UserName" Placeholder="Enter user name" />
+            <ValidationMessage For="@(() => userLogin.UserName)" />
+        </div>
+    </div>
+
+    <div class="form-group row mb-3">
+        <label class="col-md-2 col-form-label">Password: <span class="text-danger">*</span></label>
+        <div class="col-md-10">
+            <PasswordInput @bind-Value="@userLogin.Password" />
+            <ValidationMessage For="@(() => userLogin.Password)" />
+        </div>
+    </div>
+
+    <div class="row">
+        <div class="col-md-12 text-right">
+            <Button Type="ButtonType.Button" Color="ButtonColor.Secondary" Class="float-end" @onclick="ResetForm">Reset</Button>
+            <Button Type="ButtonType.Submit" Color="ButtonColor.Success" Class="float-end me-2">Login</Button>
+        </div>
+    </div>
+
+</EditForm>
+
+@code {
+    private UserLogin userLogin = new();
+    private EditContext? editContext;
+
+    protected override void OnInitialized()
+    {
+        editContext = new EditContext(userLogin);
+        base.OnInitialized();
+    }
+
+    public void HandleOnValidSubmit()
+    {
+        // additional check
+        if (editContext.Validate())
+        {
+            // do something
+            // submit the form
+            Console.WriteLine("Login successful");
+        }
+    }
+
+    private void ResetForm()
+    {
+        userLogin = new();
+        editContext = new EditContext(userLogin);
+    }
+
+    public class UserLogin
+    {
+        [Required(ErrorMessage = "User name required.")]
+        public string? UserName { get; set; }
+
+        [Required(ErrorMessage = "Password required.")]
+        public string? Password { get; set; }
+    }
+}
diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Form/PasswordInput/PasswordInput_Demo_04_Events_ValueChanged.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Form/PasswordInput/PasswordInput_Demo_04_Events_ValueChanged.razor
new file mode 100644
index 000000000..1aab225aa
--- /dev/null
+++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Form/PasswordInput/PasswordInput_Demo_04_Events_ValueChanged.razor
@@ -0,0 +1,15 @@
+<div class="mb-3">
+    <PasswordInput Value="@enteredPassword" ValueExpression="() => enteredPassword" ValueChanged="(value) => PasswordChanged(value)" />
+</div>
+<div class="mb-3">Entered password: @enteredPassword</div>
+
+@code {
+    private string? enteredPassword = null;
+
+    private void PasswordChanged(string? value)
+    {
+        enteredPassword = value;
+
+        // do something
+    }
+}
diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Index.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Index.razor
index feb8706c4..17dc506dc 100644
--- a/BlazorBootstrap.Demo.RCL/Components/Pages/Index.razor
+++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Index.razor
@@ -150,6 +150,11 @@
                 <h4 class="mb-0 fs-5 fw-semibold"><Icon Name="IconName.InputCursor" class="me-2" /> Number Input</h4>
             </a>
         </div>
+        <div class="col-sm-4 mb-2">
+            <a class="d-block pe-lg-4 text-decoration-none lh-sm" href="/form/password-input">
+                <h4 class="mb-0 fs-5 fw-semibold"><Icon Name="IconName.EyeSlashFill" class="me-2" /> Password Input <Badge Color="BadgeColor.Danger">New</Badge></h4>
+            </a>
+        </div>
         <div class="col-sm-4 mb-2">
             <a class="d-block pe-lg-4 text-decoration-none lh-sm" href="/offcanvas">
                 <h4 class="mb-0 fs-5 fw-semibold"><Icon Name="IconName.LayoutSidebarReverse" class="me-2" /> Offcanvas</h4>
@@ -299,6 +304,11 @@
                 <h4 class="mb-0 fs-5 fw-semibold"><Icon Name="IconName.InputCursor" class="me-2" /> Number Input</h4>
             </a>
         </div>
+        <div class="col-sm-4 mb-2">
+            <a class="d-block pe-lg-4 text-decoration-none lh-sm" href="/form/password-input">
+                <h4 class="mb-0 fs-5 fw-semibold"><Icon Name="IconName.EyeSlashFill" class="me-2" /> Password Input <Badge Color="BadgeColor.Danger">New</Badge></h4>
+            </a>
+        </div>
         <div class="col-sm-4 mb-2">
             <a class="d-block pe-lg-4 text-decoration-none lh-sm" href="@RouteConstants.Demos_RadioInput_Documentation">
                 <h4 class="mb-0 fs-5 fw-semibold"><Icon Name="IconName.RecordCircle" class="me-2" /> Radio Input <Badge Color="BadgeColor.Danger">New</Badge></h4>
diff --git a/BlazorBootstrap.Demo.RCL/Constants/RouteConstants.cs b/BlazorBootstrap.Demo.RCL/Constants/RouteConstants.cs
index 874eb6775..b6459f054 100644
--- a/BlazorBootstrap.Demo.RCL/Constants/RouteConstants.cs
+++ b/BlazorBootstrap.Demo.RCL/Constants/RouteConstants.cs
@@ -26,6 +26,7 @@ public static class RouteConstants
     public const string Demos_CurrencyInput_Documentation = Demos_Forms_Prefix + "/currency-input";
     public const string Demos_DateInput_Documentation = Demos_Forms_Prefix + "/date-input";
     public const string Demos_NumberInput_Documentation = Demos_Forms_Prefix + "/number-input";
+    public const string Demos_PasswordInput_Documentation = Demos_Forms_Prefix + "/password-input";
     public const string Demos_RadioInput_Documentation = Demos_Forms_Prefix + "/radio-input";
     public const string Demos_RangeInput_Documentation = Demos_Forms_Prefix + "/range-input";
     public const string Demos_SelectInput_Documentation = Demos_Forms_Prefix + "/select-input";
diff --git a/blazorbootstrap/Components/Form/PasswordInput/PasswordInput.razor b/blazorbootstrap/Components/Form/PasswordInput/PasswordInput.razor
index 4123d7373..8980ff17c 100644
--- a/blazorbootstrap/Components/Form/PasswordInput/PasswordInput.razor
+++ b/blazorbootstrap/Components/Form/PasswordInput/PasswordInput.razor
@@ -3,14 +3,17 @@
 @preservewhitespace true
 
 <div class="input-group mb-3">
-    <input 
-        @ref="@Element" 
-        type="@InputTextType"
-        id="@Id"
-        class="@BootstrapClass.FormControl"
-        disabled="@Disabled"
-        value="@Value"
-        @attributes="@AdditionalAttributes"
-        @onchange="OnChange">
-        <button type="button" class="btn btn-primary btn-sm" @onclick="OnShowHidePasswordButtonClick"><i class="bi bi-eye-fill" /></button>
+    <input @ref="@Element"
+           type="@InputTextType"
+           id="@Id"
+           class="@ClassNames"
+           style="@StyleNames"
+           value="@Value"
+           disabled="@Disabled"
+           @attributes="@AdditionalAttributes"
+           @onchange="OnChange">
+
+    <button type="button" class="@ShowHidePasswordButtonCssClass" @onclick="ShowHidePassword">
+        <i class="@ShowHidePasswordButtonIcon"></i>
+    </button>
 </div>
diff --git a/blazorbootstrap/Components/Form/PasswordInput/PasswordInput.razor.cs b/blazorbootstrap/Components/Form/PasswordInput/PasswordInput.razor.cs
index e69698788..24d050c3d 100644
--- a/blazorbootstrap/Components/Form/PasswordInput/PasswordInput.razor.cs
+++ b/blazorbootstrap/Components/Form/PasswordInput/PasswordInput.razor.cs
@@ -1,118 +1,124 @@
-using Microsoft.AspNetCore.Components.Forms;
-using Microsoft.AspNetCore.Components;
-using System.Linq.Expressions;
+namespace BlazorBootstrap;
 
-namespace BlazorBootstrap
+public partial class PasswordInput : BlazorBootstrapComponentBase
 {
-    public partial class PasswordInput
-    {
-        #region Fields and Constants
-
-        private FieldIdentifier fieldIdentifier;
+    #region Fields and Constants
 
-        private string? oldValue;
+    private FieldIdentifier fieldIdentifier;
 
-        #endregion
+    private string? oldValue;
 
-        #region Methods
+    private bool showPassword = false;
 
-        protected override async Task OnInitializedAsync()
-        {
-            oldValue = Value;
+    #endregion
 
-            AdditionalAttributes ??= new Dictionary<string, object>();
-
-            fieldIdentifier = FieldIdentifier.Create(ValueExpression);
-
-            await base.OnInitializedAsync();
-        }
+    #region Methods
 
-        protected override async Task OnParametersSetAsync()
-        {
-            if (oldValue != Value)
-            {
-                await ValueChanged.InvokeAsync(Value);
-
-                EditContext?.NotifyFieldChanged(fieldIdentifier);
+    protected override async Task OnInitializedAsync()
+    {
+        oldValue = Value;
 
-                oldValue = Value;
-            }
-        }
+        AdditionalAttributes ??= new Dictionary<string, object>();
 
-        public string InputTextType = "password";
+        fieldIdentifier = FieldIdentifier.Create(ValueExpression);
 
-        void OnShowHidePasswordButtonClick()
-        {
-            if (this.InputTextType == "password")
-                this.InputTextType = "text";
-            else
-                this.InputTextType = "password";
-        }
+        await base.OnInitializedAsync();
+    }
 
-        /// <summary>
-        /// Disables InputPassword.
-        /// </summary>
-        public void Disable() => Disabled = true;
-
-        /// <summary>
-        /// Enables InputPassword.
-        /// </summary>
-        public void Enable() => Disabled = false;
-
-        /// <summary>
-        /// This event is triggered only when the user changes the selection from the UI.
-        /// </summary>
-        /// <param name="args"></param>
-        private async Task OnChange(ChangeEventArgs args)
+    protected override async Task OnParametersSetAsync()
+    {
+        if (oldValue != Value)
         {
-            Value = args.Value?.ToString();
-
             await ValueChanged.InvokeAsync(Value);
 
             EditContext?.NotifyFieldChanged(fieldIdentifier);
 
             oldValue = Value;
         }
+    }
 
-        #endregion
-
-        #region Properties, Indexers
-
-        protected override string? ClassNames =>
-            BuildClassNames(Class,
-                (BootstrapClass.FormControl, true));
-
-        /// <summary>
-        /// Gets or sets the disabled state.
-        /// </summary>
-        /// <remarks>
-        /// Default value is false.
-        /// </remarks>
-        [Parameter]
-        public bool Disabled { get; set; }
-
-        [CascadingParameter] private EditContext EditContext { get; set; } = default!;
-
-        private string fieldCssClasses => EditContext?.FieldCssClass(fieldIdentifier) ?? "";
-
-
-        /// <summary>
-        /// Gets or sets the value.
-        /// </summary>
-        /// <remarks>
-        /// Default value is null.
-        /// </remarks>
-        [Parameter]
-        public string? Value { get; set; } = default!;
+    /// <summary>
+    /// Disables InputPassword.
+    /// </summary>
+    public void Disable() => Disabled = true;
+
+    /// <summary>
+    /// Enables InputPassword.
+    /// </summary>
+    public void Enable() => Disabled = false;
+
+    /// <summary>
+    /// This event is triggered only when the user changes the selection from the UI.
+    /// </summary>
+    /// <param name="args"></param>
+    private async Task OnChange(ChangeEventArgs args)
+    {
+        oldValue = Value;
 
-        /// <summary>
-        /// This event is fired when the inputpassword value changes.
-        /// </summary>
-        [Parameter]
-        public EventCallback<string?> ValueChanged { get; set; } = default!;
+        Value = args.Value?.ToString() ?? string.Empty; // object
 
-        [Parameter] public Expression<Func<string?>> ValueExpression { get; set; } = default!;
+        await ValueChanged.InvokeAsync(Value);
 
-        #endregion
+        EditContext?.NotifyFieldChanged(fieldIdentifier);
     }
+
+    private void ShowHidePassword() => showPassword = !showPassword;
+
+    #endregion
+
+    #region Properties, Indexers
+
+    protected override string? ClassNames =>
+        BuildClassNames(
+            Class,
+            (BootstrapClass.FormControl, true),
+            (EditContext?.FieldCssClass(fieldIdentifier) ?? string.Empty, true)
+        );
+
+    /// <summary>
+    /// Gets or sets the disabled state.
+    /// </summary>
+    /// <remarks>
+    /// Default value is false.
+    /// </remarks>
+    [Parameter]
+    public bool Disabled { get; set; }
+
+    /// <summary>
+    /// Gets the associated <see cref="Microsoft.AspNetCore.Components.Forms.EditContext" />.
+    /// </summary>
+    [CascadingParameter]
+    private EditContext EditContext { get; set; } = default!;
+
+    private string InputTextType => showPassword ? "text" : "password";
+
+    /// <summary>
+    /// Gets or sets the show/hide password button CSS class.
+    /// </summary>
+    /// <remarks>
+    /// Default value is `btn btn-primary btn-sm`.
+    /// </remarks>
+    [Parameter]
+    public string? ShowHidePasswordButtonCssClass { get; set; } = "btn border-top border-end border-bottom border border-start-0"; //""btn btn-light border";
+
+    private string ShowHidePasswordButtonIcon => showPassword ? "bi bi-eye-fill" : "bi bi-eye-slash-fill";
+
+    /// <summary>
+    /// Gets or sets the value.
+    /// </summary>
+    /// <remarks>
+    /// Default value is null.
+    /// </remarks>
+    [Parameter]
+    public string? Value { get; set; }
+
+    /// <summary>
+    /// This event is fired when the PasswordInput value changes.
+    /// </summary>
+    [Parameter]
+    public EventCallback<string?> ValueChanged { get; set; }
+
+    [Parameter] public Expression<Func<string?>> ValueExpression { get; set; } = default!;
+
+    #endregion
 }
diff --git a/blazorbootstrap/Components/Form/RadioInput/RadioInput.razor.cs b/blazorbootstrap/Components/Form/RadioInput/RadioInput.razor.cs
index 902ddf906..a5fc7f966 100644
--- a/blazorbootstrap/Components/Form/RadioInput/RadioInput.razor.cs
+++ b/blazorbootstrap/Components/Form/RadioInput/RadioInput.razor.cs
@@ -32,12 +32,11 @@ protected override void OnInitialized()
     private async Task OnChange(ChangeEventArgs e)
     {
         var oldValue = Value;
+
         var newValue = string.Equals(e.Value?.ToString(), "on");
 
         await ValueChanged.InvokeAsync(newValue);
 
-        Console.WriteLine($"Old value: {oldValue}, New value: {e.Value}");
-
         EditContext?.NotifyFieldChanged(fieldIdentifier);
     }