page TogglePasswordcomponent { seo { title = "TogglePassword component" description = "Accessible password field with optional show and hide controls." } view {
W WRNexusJS
advanced-forms component

TogglePassword

Accessible password field with optional show and hide controls.

@wrnexus/ui 0.3.624 props0 slots3 events

Usage

Components are auto-discovered. Use the component directly in any .wrn view:

<TogglePassword
  size="default"
  color="primary"
  label="Password"
  name="password"
  value="value"
/>

Legacy mount name: data-component="TogglePassword".

Props and attributes

PropTypeRequirementDefault
sizestringOptional"default"
colorstringOptional"primary"
labelstringOptional"Password"
namestringOptional"password"
valuestringOptional""
placeholderstringOptional"Enter your password"
autocompletestringOptional"current-password"
minlengthstringOptional""
maxlengthstringOptional""
patternstringOptional"(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9]).{8,}"
fieldsstringOptional[]
visiblebooleanOptionalfalse
toggleablebooleanOptionaltrue
toggleModestringOptional"button"
checkboxLabelstringOptional"Show password"
showLabelstringOptional"Show password"
hideLabelstringOptional"Hide password"
disabledbooleanOptionalfalse
readonlybooleanOptionalfalse
requiredbooleanOptionalfalse
invalidbooleanOptionalfalse
helpTextstringOptional""
validationMessagestringOptional""
classstringOptional""

Slots

This component does not declare a slot.

Events

  • input
  • change
  • toggle

Source contract

Installed source: components/TogglePassword.wrn

component TogglePassword {
  props {
    size = "default"
    color = "primary"
    label = "Password"
    name = "password"
    value = ""
    placeholder = "Enter your password"
    autocomplete = "current-password"
    minlength = ""
    maxlength = ""
    pattern = "(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9]).{8,}"
    fields = []
    visible = false
    toggleable = true
    toggleMode = "button"
    checkboxLabel = "Show password"
    showLabel = "Show password"
    hideLabel = "Hide password"
    disabled = false
    readonly = false
    required = false
    invalid = false
    helpText = ""
    validationMessage = ""
    class = ""
    @event input = function
    @event change = function
    @event toggle = function
  }

  state revealed = visible

  functions {
    function toggleVisibility() {
      if (disabled || readonly || !toggleable) {
        return
      }
      revealed = !revealed
    }

    function fieldId(field, index) {
      return field.id || field.name || name + "-" + index
    }

    function fieldName(field, index) {
      return field.name || name + "-" + index
    }
  }

  view {
        <fieldset
      class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--toggle-password {invalid ? 'wire-next--invalid' : ''} {disabled ? 'wire-next--disabled' : ''} {class}"
      data-wrn-toggle-password
      data-visible="{revealed ? 'true' : 'false'}"
    >
      {#if fields.length}
        <div class="wire-next__password-fields">
          {#each fields as field, index}
            <div class="wire-next__password-field">
        <label for="{fieldId(field, index)}">{field.label || label}</label>
        <div class="wire-next__password-control">
        <input
                  id="{fieldId(field, index)}"
                  type="{revealed ? 'text' : 'password'}"
                  name="{fieldName(field, index)}"
                  value="{field.value || ''}"
                  placeholder="{field.placeholder || placeholder}"
                  autocomplete="{field.autocomplete || autocomplete}"
                  minlength="{field.minlength || minlength}"
                  maxlength="{field.maxlength || maxlength}"
                  pattern="{field.pattern || pattern}"
                  disabled="{disabled || field.disabled}"
                  readonly="{readonly || field.readonly}"
                  required="{required || field.required}"
                  aria-invalid="{invalid ? 'true' : 'false'}"
                  @input="$emit('input', { name: event.target.name, value: event.target.value, visible: revealed })"
                  @change="$emit('change', { name: event.target.name, value: event.target.value, visible: revealed })"
                />
                {#if toggleable && toggleMode === "button"}
                  <button
                    type="button"
                    class="wire-next__password-toggle"
                    aria-label="{revealed ? hideLabel : showLabel}"
                    title="{revealed ? hideLabel : showLabel}"
                    aria-pressed="{revealed ? 'true' : 'false'}"
                    disabled="{disabled || readonly}"
                    @click="toggleVisibility(); $emit('toggle', { visible: revealed })"
                  >
        <span class="wire-next__password-icon wire-next__password-icon--show" aria-hidden="true">
        </span>
        </button>
                {/if}
              </div>
        </div>
          {/each}
        </div>
      {:else}
        <label for="{name}-password">{label}</label>
        <div class="wire-next__password-control">
        <input
            {...attrs}
            id="{name}-password"
            type="{revealed ? 'text' : 'password'}"
            name="{name}"
            value="{value}"
            placeholder="{placeholder}"
            autocomplete="{autocomplete}"
            minlength="{minlength}"
            maxlength="{maxlength}"
            pattern="{pattern}"
            disabled="{disabled}"
            readonly="{readonly}"
            required="{required}"
            aria-invalid="{invalid ? 'true' : 'false'}"
            aria-describedby="{validationMessage ? name + '-validation' : helpText ? name + '-help' : ''}"
            @input="$emit('input', { value: event.target.value, visible: revealed })"
            @change="$emit('change', { value: event.target.value, visible: revealed })"
          />
          {#if toggleable && toggleMode === "button"}
            <button
              type="button"
              class="wire-next__password-toggle"
              aria-label="{revealed ? hideLabel : showLabel}"
              title="{revealed ? hideLabel : showLabel}"
              aria-pressed="{revealed ? 'true' : 'false'}"
              disabled="{disabled || readonly}"
              @click="toggleVisibility(); $emit('toggle', { visible: revealed })"
            >
        <span class="wire-next__password-icon wire-next__password-icon--show" aria-hidden="true">
        </span>
        </button>
          {/if}
        </div>
      {/if}
      {#if toggleable && toggleMode === "checkbox"}
        <label class="wire-next__password-checkbox">
        <input
            type="checkbox"
            checked="{revealed}"
            disabled="{disabled || readonly}"
            @change="revealed = event.target.checked; $emit('toggle', { visible: revealed })"
          />
        <span>{checkboxLabel}</span>
        </label>
      {/if}
      {#if helpText && !validationMessage}<small id="{name}-help">{helpText}</small>{/if}
      <small
        id="{name}-validation"
        class="wire-next__validation"
        data-error="{name}"
      >{validationMessage}</small>
        </fieldset>
    }
}
} }