Exclusivobeta

Password Field <mv-password-field>

Campo de senha que mantém o seu <input type="password"> nativo (assim o preenchimento automático, os gerenciadores de senhas e o envio do formulário simplesmente funcionam) e acrescenta um verdadeiro botão mostrar/ocultar que preserva a posição do cursor e volta a ocultar no envio, um aviso de Caps Lock enquanto o campo está em foco e, para novas senhas, uma checklist das regras que você declarar, além de uma estimativa de força em palavras que valoriza o comprimento e não se deixa enganar por palavras comuns, anos, sequências e repetições. O que os outros não fazem: as regras aparecem antes da primeira tecla, para ninguém falhar de surpresa, o progresso é anunciado quando o usuário faz uma pausa (nunca a cada caractere), as regras controlam a validade nativa do campo para que o formulário se recuse a ser enviado, uma opção match confirma um segundo campo, o autocomplete certo (new-password ou current-password) é definido para você, e uma senha revelada fica longe dos corretores ortográficos na nuvem.

CategoriaFormulários
TipoWeb Component (<mv-password-field>)
Statusbeta
Keywordsexclusive, light, password, form, validation, strength, caps-lock, show-password, sign-up, autocomplete, a11y

When to use

  • A sign-up, password reset or change-password form needs visible rules and a strength estimate
  • A sign-in form needs a show/hide button and a Caps Lock warning without breaking password managers
  • A new password must be typed twice and the form should block submission until both match
  • The site has its own password policy, such as a minimum length or a ban on the user's name

Avoid when

  • A complete log in, sign up, forgot password and code flow is needed as one screen → use Auth instead
  • The secret is a short numeric one-time code sent by SMS or email → use OTP instead
  • The value is an API key or token that is shown once and copied, not typed → use Reveal Once instead

Instalação

node scripts/add.mjs password-field --out ./src/marvelous

Agente de IA com o servidor MCP do Marvelous UI: install_components({ slugs: ["password-field"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).

Arquivos copiados (dependências incluídas): tokens/tokens.css, core/base.css, core/dom.js, core/element.js, components/password-field/password-field.js, components/password-field/password-field.css.

Uso

Início rápido, a menor marcação que funciona:

<mv-password-field purpose="new"><input name="password" aria-label="Password" required></mv-password-field>

Marcação de referência, para usar como ponto de partida e personalizar com atributos, data-* e variáveis CSS:

<div id="mv-pw-demo" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,19rem),1fr));gap:1.25rem;width:100%;max-width:880px;align-items:start">
  <form class="mv-pw-demo-card" id="mv-pw-demo-signup" style="display:grid;gap:1rem;padding:1.5rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-xl);background:var(--mv-surface);box-shadow:var(--mv-shadow-sm)">
    <div>
      <h3 style="margin:0;font-size:var(--mv-text-lg)">Create your account</h3>
      <p style="margin:.25rem 0 0;color:var(--mv-fg-muted);font-size:var(--mv-text-sm)">Start your 14-day trial of Lumen Studio. No card needed.</p>
    </div>
    <div class="mv-field">
      <label class="mv-label" for="mv-pw-demo-email">Work email</label>
      <input class="mv-input" id="mv-pw-demo-email" type="email" name="email" value="[email protected]" autocomplete="username" required>
    </div>
    <div class="mv-field">
      <label class="mv-label" for="mv-pw-demo-new">Password</label>
      <mv-password-field purpose="new" rules="length:12 upper lower digit symbol">
        <input id="mv-pw-demo-new" name="password" required>
      </mv-password-field>
    </div>
    <div class="mv-field">
      <label class="mv-label" for="mv-pw-demo-confirm">Confirm password</label>
      <mv-password-field match="#mv-pw-demo-new">
        <input id="mv-pw-demo-confirm" name="password-confirm" required>
      </mv-password-field>
    </div>
    <button class="mv-button" type="submit">Create account</button>
    <p id="mv-pw-demo-done" hidden style="margin:0;color:var(--mv-fg-muted);font-size:var(--mv-text-sm)"></p>
  </form>

  <form class="mv-pw-demo-card" style="display:grid;gap:1rem;padding:1.5rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-xl);background:var(--mv-surface);box-shadow:var(--mv-shadow-sm)" onsubmit="event.preventDefault()">
    <div>
      <h3 style="margin:0;font-size:var(--mv-text-lg)">Welcome back</h3>
      <p style="margin:.25rem 0 0;color:var(--mv-fg-muted);font-size:var(--mv-text-sm)">Sign in to continue to your workspace.</p>
    </div>
    <div class="mv-field">
      <label class="mv-label" for="mv-pw-demo-user">Email</label>
      <input class="mv-input" id="mv-pw-demo-user" type="email" name="email" value="[email protected]" autocomplete="username">
    </div>
    <div class="mv-field">
      <div class="mv-field-header">
        <label class="mv-label" for="mv-pw-demo-current">Password</label>
        <a href="#" style="font-size:var(--mv-text-xs);color:var(--mv-fg-muted)">Forgot password?</a>
      </div>
      <mv-password-field>
        <input id="mv-pw-demo-current" name="password" value="Kyoto-in-autumn-88" required>
      </mv-password-field>
    </div>
    <button class="mv-button" data-variant="outline" type="submit">Sign in</button>
  </form>
</div>

<script type="module">
  const signup = document.getElementById("mv-pw-demo-signup");
  const field = signup.querySelector("mv-password-field[purpose]");
  const email = signup.querySelector("#mv-pw-demo-email");
  // A custom rule on top of the declared ones: the password must not contain the email's name.
  field.customRules = [{
    id: "no-name",
    label: "Doesn’t include your name",
    test: (value) => {
      const name = email.value.split("@")[0].split(/[._-]/)[0].toLowerCase();
      return (name.length < 3 || !value.toLowerCase().includes(name));
    },
  }];
  signup.addEventListener("submit", (e) => {
    e.preventDefault();
    const done = document.getElementById("mv-pw-demo-done");
    done.hidden = false;
    done.textContent = `Account created for ${email.value}.`;
  });
</script>

API

Attributes

NameTipoDefaultDescription
purposenew | currentcurrentnew: sign-up, reset or change (autocomplete="new-password", checklist and strength). current: sign-in (autocomplete="current-password", reveal and Caps Lock only). Without it, an input already marked autocomplete="new-password" counts as new.
rulesstringlength:12Space-separated rules shown as a checklist when purpose="new": length:N (counted in visible characters, emoji included), upper, lower, digit, symbol (any character that is not a letter or digit, spaces included). Set rules="" to show the strength estimate alone.
matchCSS selectorMakes this a confirmation field: the input (or the mv-password-field) it points to must hold the same value. Shows “Passwords match” or “Passwords don’t match” once typing starts, and sets the validity. Implies new-password and no checklist.
labelstringPasswordAccessible name of the input the component creates when you give it none (prefer your own <input> with a <label for>).
namestringpasswordForm name of the created input (ignored when you provide your own <input>).

Properties

NameTipoDescription
stringsobjectOverride any default text: label, show, caps, length ({ one, other } with {n}), upper, lower, digit, symbol, met / unmet ({rule}), strength ({level}), weak, fair, strong, hint, common, sequence, repeat, summary ({met}, {total}, {level}), invalid ({list}), match, mismatch. Numbers, plurals and lists follow the nearest lang (Intl). Can be set before the element is defined.
customRulesArray<{ id, label, test(value) }>Extra rules checked after the declared ones (e.g. “Doesn’t include your name”); test returns true when met; no rule counts as met while the field is empty. Can be set before the element is defined.
inputHTMLInputElementThe native input (read-only).
visiblebooleanWhether the password is currently shown (read-only; use reveal()).
state{ valid, met, total, strength, match }Current result: strength is "weak" | "fair" | "strong" | null, match is true/false or null without match (read-only).

Methods

NameDescription
reveal(show = true)Show or hide the password, keeping the caret and selection; returns the new visibility.
estimate(value)Named export: pure, server-safe strength estimate, returns null or { level, score (1-3), bits, tip }.

Events

NameDescription
mv-changeOn every edit; detail = state ({ valid, met, total, strength, match }).
mv-toggleBefore showing or hiding; detail = { visible }. Cancelable (e.g. a kiosk policy that forbids revealing). Hiding on submit is not cancelable.

Content structure

NameDescription
inputYour own <input> (recommended: keeps id, name, required, minlength and your <label for>). It is forced to type="password" and gets the right autocomplete. Without one, an input is created.

CSS classes

NameDescription
mv-password-field-control / -input / -toggleBordered row, the native input, the show/hide button.
mv-password-field-capsCaps Lock warning (hidden while off or unfocused).
mv-password-field-strength / -bars / -level / -tipStrength row: three segments (aria-hidden), the level in words, a tip or hint. data-level="weak|fair|strong".
mv-password-field-rules / -ruleChecklist; each rule has data-met="true|false".
mv-password-field-matchConfirmation line; data-ok="true|false".

CSS variables

NameDefaultDescription
--mv-password-field-radiusvar(--mv-radius-md)Corner radius of the field.
--mv-password-field-weakvar(--mv-danger)Segment color for a weak password.
--mv-password-field-fairvar(--mv-warning)Segment color for a fair password.
--mv-password-field-strongvar(--mv-success)Segment color for a strong password and met rules.

Accessibility

The input stays a native <input type="password">, labelled by your <label for> (or by label when the component creates it). The reveal control is a real <button type="button"> named “Show password” whose state is aria-pressed (the name never changes, only the state and the eye icon); a pointer click keeps focus and caret in the field, the keyboard reaches it with Tab and Space or Enter. The requirement list is linked with aria-describedby, so it is read on focus before any typing, and each rule carries a hidden “Met: …” or “Not met: …” text instead of relying on the icon or color. Progress is announced by a polite status region once the user pauses for a second (“3 of 5 requirements met. Strength: Fair.”), only while the field has focus and never twice in a row; nothing is spoken per keystroke. Caps Lock (read from the key and pointer events while focused) shows a warning that is added to the description and announced once. Strength is written in words next to the segments, which are aria-hidden. The rules and the match set the input's custom validity, so the browser blocks submission and names what is missing; unmet rules only turn red after the browser flags the field (:user-invalid), not while typing. Edge's built-in reveal is hidden to avoid two eye buttons; password manager icons are left alone. The revealed text has spellcheck, autocorrect and autocapitalize off. Forced colors: bordered segments filled with CanvasText, visible focus outline. Transitions are color-only and switch off with reduced motion. Without JS the native field still works.

Esta página foi traduzida com IA. Informar um problema de tradução