
Form Security
- 60 installs
- 8 repo stars
- Updated August 4, 2026
- bbeierle12/skill-mcp-claude
form-security is a Claude Code skill that provides security patterns for web forms, including autocomplete attributes, CSRF protection, and XSS prevention for authentication and payment forms.
About
form-security is a Claude Code skill covering security patterns for web forms. It documents the full autocomplete attribute specification for identity, authentication, address, and payment fields, plus CSRF tokens, XSS prevention, and never blocking paste. A developer loads it when building authentication, payment, or other sensitive-data forms. It focuses on password-manager compatibility and preventing common form attacks.
- Correct autocomplete attributes so password managers autofill reliably
- CSRF token and XSS-prevention patterns for auth and payment forms
- Password-field rules: current-password vs new-password vs one-time-code
Form Security by the numbers
- 60 all-time installs (skills.sh)
- Ranked #1,224 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
form-security capabilities & compatibility
- Capabilities
- form security · csrf protection · xss prevention · form accessibility
- Use cases
- security audit · frontend
What form-security says it does
Security-first patterns for web forms. Ensures password manager compatibility, prevents common attacks, and protects user data.
Allow paste (never disable!)
npx skills add https://github.com/bbeierle12/skill-mcp-claude --skill form-securityAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 60 |
|---|---|
| repo stars | ★ 8 |
| Last updated | August 4, 2026 |
| Repository | bbeierle12/skill-mcp-claude ↗ |
What it does
Harden auth and payment forms with correct autocomplete, CSRF tokens, and XSS prevention.
Who is it for?
Developers building login, registration, and payment forms that handle sensitive data.
Skip if: General UI styling or non-sensitive forms where security is not a concern.
When should I use this skill?
Implementing authentication forms, payment forms, or any form handling sensitive data.
What you get
Auth and payment forms with correct autocomplete, CSRF tokens, and paste-friendly, XSS-safe inputs.
- Autocomplete attribute reference
- CSRF token form pattern
- Secure password and payment field markup
By the numbers
- autocomplete specification lists 40+ token values across identity, auth, address, and payment
Files
Form Security
Security-first patterns for web forms. Ensures password manager compatibility, prevents common attacks, and protects user data.
Quick Start
// The 3 critical security patterns
<form>
{/* 1. Autocomplete for password managers */}
<input type="email" autoComplete="email" />
<input type="password" autoComplete="current-password" />
{/* 2. CSRF token */}
<input type="hidden" name="_csrf" value={csrfToken} />
{/* 3. Allow paste (never disable!) */}
<input type="password" /> {/* No onPaste handler blocking */}
</form>Autocomplete Attributes
Why It Matters
- 1Password, LastPass, Bitwarden rely on
autocompleteto identify fields - Without correct values, password managers fail silently
- Users abandon forms when autofill doesn't work
- Security improves when users can use unique, strong passwords
The Autocomplete Specification
// autocomplete-config.ts
export const AUTOCOMPLETE = {
// ===== IDENTITY =====
name: 'name', // Full name
honorificPrefix: 'honorific-prefix', // Mr., Mrs., Dr.
givenName: 'given-name', // First name
additionalName: 'additional-name', // Middle name
familyName: 'family-name', // Last name
honorificSuffix: 'honorific-suffix', // Jr., III
nickname: 'nickname',
// ===== AUTHENTICATION (CRITICAL) =====
email: 'email',
username: 'username',
currentPassword: 'current-password', // LOGIN forms
newPassword: 'new-password', // REGISTRATION + RESET forms
oneTimeCode: 'one-time-code', // 2FA/OTP codes
// ===== CONTACT =====
tel: 'tel', // Full phone
telCountryCode: 'tel-country-code',
telNational: 'tel-national',
telAreaCode: 'tel-area-code',
telLocal: 'tel-local',
telExtension: 'tel-extension',
// ===== ADDRESS =====
streetAddress: 'street-address', // Full street (may be multiline)
addressLine1: 'address-line1', // Street line 1
addressLine2: 'address-line2', // Apt, Suite, etc.
addressLine3: 'address-line3',
addressLevel1: 'address-level1', // State/Province
addressLevel2: 'address-level2', // City
addressLevel3: 'address-level3', // District
addressLevel4: 'address-level4', // Neighborhood
postalCode: 'postal-code',
country: 'country',
countryName: 'country-name',
// ===== PAYMENT (CRITICAL) =====
ccName: 'cc-name', // Name on card
ccGivenName: 'cc-given-name',
ccFamilyName: 'cc-family-name',
ccNumber: 'cc-number', // Card number
ccExp: 'cc-exp', // Expiry (MM/YY)
ccExpMonth: 'cc-exp-month', // Expiry month
ccExpYear: 'cc-exp-year', // Expiry year
ccCsc: 'cc-csc', // CVV/CVC
ccType: 'cc-type', // Visa, Mastercard, etc.
// ===== ORGANIZATION =====
organization: 'organization',
organizationTitle: 'organization-title', // Job title
// ===== DATES =====
bday: 'bday', // Full birthday
bdayDay: 'bday-day',
bdayMonth: 'bday-month',
bdayYear: 'bday-year',
// ===== OTHER =====
sex: 'sex', // Gender
url: 'url', // Website
photo: 'photo', // Photo URL
language: 'language',
// ===== SPECIAL VALUES =====
off: 'off', // Disable autofill (use sparingly!)
on: 'on' // Enable autofill (default)
} as const;
export type AutocompleteValue = typeof AUTOCOMPLETE[keyof typeof AUTOCOMPLETE];Critical Password Patterns
// ✅ LOGIN: Use current-password
<form action="/login">
<input type="email" autoComplete="email" />
<input type="password" autoComplete="current-password" />
</form>
// ✅ REGISTRATION: Use new-password (BOTH fields)
<form action="/register">
<input type="email" autoComplete="email" />
<input type="password" autoComplete="new-password" />
<input type="password" autoComplete="new-password" /> {/* confirm */}
</form>
// ✅ PASSWORD RESET: Use new-password
<form action="/reset-password">
<input type="password" autoComplete="new-password" />
<input type="password" autoComplete="new-password" /> {/* confirm */}
</form>
// ✅ CHANGE PASSWORD: current + new
<form action="/change-password">
<input type="password" autoComplete="current-password" /> {/* old */}
<input type="password" autoComplete="new-password" /> {/* new */}
<input type="password" autoComplete="new-password" /> {/* confirm */}
</form>
// ✅ 2FA/OTP: Use one-time-code
<form action="/verify-2fa">
<input
type="text"
inputMode="numeric"
autoComplete="one-time-code"
pattern="[0-9]*"
/>
</form>Why new-password for Registration
// ❌ WRONG: Using current-password on registration
// Password manager tries to fill EXISTING password
<input type="password" autoComplete="current-password" />
// ✅ CORRECT: Using new-password
// Password manager offers to GENERATE a new password
<input type="password" autoComplete="new-password" />Payment Form Pattern
<form action="/checkout">
<input
type="text"
autoComplete="cc-name"
placeholder="Name on card"
/>
<input
type="text"
inputMode="numeric"
autoComplete="cc-number"
placeholder="Card number"
/>
<input
type="text"
autoComplete="cc-exp"
placeholder="MM/YY"
/>
<input
type="text"
inputMode="numeric"
autoComplete="cc-csc"
placeholder="CVV"
/>
</form>Address Form Pattern
<fieldset>
<legend>Shipping Address</legend>
<input autoComplete="name" placeholder="Full name" />
<input autoComplete="address-line1" placeholder="Street address" />
<input autoComplete="address-line2" placeholder="Apt, Suite, etc." />
<input autoComplete="address-level2" placeholder="City" />
<input autoComplete="address-level1" placeholder="State" />
<input autoComplete="postal-code" placeholder="ZIP code" />
<select autoComplete="country">
<option value="US">United States</option>
{/* ... */}
</select>
</fieldset>CSRF Protection
Token Generation (Server)
// server/csrf.ts
import crypto from 'crypto';
export function generateCsrfToken(): string {
return crypto.randomBytes(32).toString('hex');
}
// Store in session
app.use((req, res, next) => {
if (!req.session.csrfToken) {
req.session.csrfToken = generateCsrfToken();
}
res.locals.csrfToken = req.session.csrfToken;
next();
});Token Inclusion (Client)
// React pattern
function Form({ csrfToken }) {
return (
<form method="POST">
<input type="hidden" name="_csrf" value={csrfToken} />
{/* form fields */}
</form>
);
}
// With fetch
async function submitForm(data: FormData) {
const response = await fetch('/api/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken
},
body: JSON.stringify(data)
});
}Token Validation (Server)
// Middleware
function validateCsrf(req, res, next) {
const tokenFromBody = req.body._csrf;
const tokenFromHeader = req.headers['x-csrf-token'];
const sessionToken = req.session.csrfToken;
const providedToken = tokenFromBody || tokenFromHeader;
if (!providedToken || providedToken !== sessionToken) {
return res.status(403).json({ error: 'Invalid CSRF token' });
}
next();
}
// Apply to state-changing routes
app.post('/api/*', validateCsrf);
app.put('/api/*', validateCsrf);
app.delete('/api/*', validateCsrf);Double Submit Cookie Pattern
// Alternative: Cookie + Header must match
// Server sets cookie
res.cookie('csrf', token, { httpOnly: false, sameSite: 'strict' });
// Client reads cookie and sends in header
const csrfToken = document.cookie
.split('; ')
.find(row => row.startsWith('csrf='))
?.split('=')[1];
fetch('/api/submit', {
headers: { 'X-CSRF-Token': csrfToken }
});
// Server validates cookie === headerXSS Prevention
Never Trust User Input
// ❌ DANGEROUS: Directly rendering user input
<div dangerouslySetInnerHTML={{ __html: userInput }} />
// ✅ SAFE: React auto-escapes by default
<div>{userInput}</div>
// ✅ SAFE: Explicit sanitization when HTML needed
import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userInput) }} />Input Sanitization
// sanitize.ts
import DOMPurify from 'dompurify';
// For plain text (strip all HTML)
export function sanitizeText(input: string): string {
return DOMPurify.sanitize(input, { ALLOWED_TAGS: [] });
}
// For rich text (allow safe HTML)
export function sanitizeHtml(input: string): string {
return DOMPurify.sanitize(input, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'br'],
ALLOWED_ATTR: ['href', 'title']
});
}
// For URLs
export function sanitizeUrl(url: string): string {
const sanitized = DOMPurify.sanitize(url);
// Only allow http(s) and relative URLs
if (/^(https?:\/\/|\/[^\/])/i.test(sanitized)) {
return sanitized;
}
return '';
}Content Security Policy
// Set CSP headers (Express)
app.use((req, res, next) => {
res.setHeader(
'Content-Security-Policy',
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"
);
next();
});Password Field Security
Never Disable Paste
// ❌ DANGEROUS: Disabling paste
<input type="password" onPaste={(e) => e.preventDefault()} />
// ✅ CORRECT: Allow paste (password managers need it!)
<input type="password" />Password Visibility Toggle
function PasswordInput({ ...props }) {
const [visible, setVisible] = useState(false);
return (
<div className="password-input">
<input
type={visible ? 'text' : 'password'}
{...props}
/>
<button
type="button"
onClick={() => setVisible(!visible)}
aria-label={visible ? 'Hide password' : 'Show password'}
>
{visible ? <EyeOffIcon /> : <EyeIcon />}
</button>
</div>
);
}Don't Log Passwords
// ❌ DANGEROUS
console.log('Login attempt:', { email, password });
// ✅ SAFE
console.log('Login attempt:', { email, password: '[REDACTED]' });Secure Form Submission
HTTPS Only
// Redirect HTTP to HTTPS
app.use((req, res, next) => {
if (req.headers['x-forwarded-proto'] !== 'https') {
return res.redirect(`https://${req.headers.host}${req.url}`);
}
next();
});Secure Cookies
// Set secure cookie flags
res.cookie('session', sessionId, {
httpOnly: true, // Prevent XSS access
secure: true, // HTTPS only
sameSite: 'strict', // CSRF protection
maxAge: 3600000 // 1 hour
});Rate Limiting
import rateLimit from 'express-rate-limit';
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // 5 attempts
message: 'Too many login attempts. Please try again later.'
});
app.post('/login', loginLimiter, handleLogin);Security Checklist
Authentication Forms
- [ ]
autocomplete="email"on email field - [ ]
autocomplete="current-password"on login password - [ ]
autocomplete="new-password"on registration/reset password - [ ]
autocomplete="one-time-code"on 2FA field - [ ] Paste is allowed on all password fields
- [ ] CSRF token included
- [ ] Rate limiting enabled
- [ ] HTTPS enforced
Payment Forms
- [ ]
autocomplete="cc-*"attributes on all card fields - [ ]
inputMode="numeric"on number fields - [ ] CSRF token included
- [ ] PCI DSS compliance (use Stripe/Braintree)
- [ ] No card data logged
All Forms
- [ ] Input validation (client + server)
- [ ] Output encoding (XSS prevention)
- [ ] Error messages don't leak sensitive info
- [ ] Secure cookie settings
- [ ] CSP headers configured
File Structure
form-security/
├── SKILL.md
├── references/
│ ├── autocomplete-spec.md # Full autocomplete reference
│ └── csrf-patterns.md # CSRF implementation patterns
└── scripts/
├── autocomplete-config.ts # Autocomplete constants
├── csrf-token.ts # CSRF token utilities
├── sanitize.ts # Input sanitization
└── secure-input.tsx # Secure input componentsReference
references/autocomplete-spec.md— Complete autocomplete attribute referencereferences/csrf-patterns.md— CSRF implementation patterns
{
"name": "form-security",
"description": "Security patterns for web forms including autocomplete attributes for password managers, CSRF protection, XSS prevention, and input sanitization. Use when implementing authentication forms, payment forms, or any form handling sensitive data.",
"tags": [
"forms",
"security",
"web",
"code-generation"
],
"sub_skills": [],
"source": "claude-user",
"type": "template",
"depends_on": [],
"enhances": [
"form-react",
"form-vue",
"form-vanilla"
],
"last_reviewed_at": "2026-06-07",
"review_score": 66,
"relevance_tier": "B"
}
/**
* Autocomplete Configuration
*
* Complete autocomplete attribute values for password manager compatibility.
* Based on WHATWG HTML Standard: https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill
*
* @module autocomplete-config
*/
// =============================================================================
// AUTOCOMPLETE VALUES
// =============================================================================
/**
* Complete autocomplete attribute values
*
* @example
* ```tsx
* import { AUTOCOMPLETE } from './autocomplete-config';
*
* <input type="email" autoComplete={AUTOCOMPLETE.email} />
* <input type="password" autoComplete={AUTOCOMPLETE.currentPassword} />
* ```
*/
export const AUTOCOMPLETE = {
// =========================================================================
// IDENTITY
// =========================================================================
/** Full name */
name: 'name',
/** Title/prefix (Mr., Mrs., Dr.) */
honorificPrefix: 'honorific-prefix',
/** First name */
givenName: 'given-name',
/** Middle name */
additionalName: 'additional-name',
/** Last name */
familyName: 'family-name',
/** Suffix (Jr., III) */
honorificSuffix: 'honorific-suffix',
/** Nickname */
nickname: 'nickname',
// =========================================================================
// AUTHENTICATION (CRITICAL FOR PASSWORD MANAGERS)
// =========================================================================
/** Email address */
email: 'email',
/** Username */
username: 'username',
/**
* Current/existing password - USE FOR LOGIN FORMS
* Password managers will offer to fill existing credentials
*/
currentPassword: 'current-password',
/**
* New password - USE FOR REGISTRATION AND PASSWORD RESET
* Password managers will offer to generate a new password
*/
newPassword: 'new-password',
/**
* One-time code - USE FOR 2FA/OTP FIELDS
* Password managers and SMS autofill will recognize this
*/
oneTimeCode: 'one-time-code',
// =========================================================================
// CONTACT - PHONE
// =========================================================================
/** Full phone number */
tel: 'tel',
/** Country code (e.g., +1) */
telCountryCode: 'tel-country-code',
/** National number (without country code) */
telNational: 'tel-national',
/** Area code */
telAreaCode: 'tel-area-code',
/** Local number */
telLocal: 'tel-local',
/** Extension */
telExtension: 'tel-extension',
// =========================================================================
// ADDRESS
// =========================================================================
/** Full street address (may be multiline) */
streetAddress: 'street-address',
/** Street address line 1 */
addressLine1: 'address-line1',
/** Street address line 2 (Apt, Suite, etc.) */
addressLine2: 'address-line2',
/** Street address line 3 */
addressLine3: 'address-line3',
/** State, Province, Region */
addressLevel1: 'address-level1',
/** City */
addressLevel2: 'address-level2',
/** District */
addressLevel3: 'address-level3',
/** Neighborhood */
addressLevel4: 'address-level4',
/** ZIP/Postal code */
postalCode: 'postal-code',
/** Country code (ISO 3166-1 alpha-2) */
country: 'country',
/** Country name */
countryName: 'country-name',
// =========================================================================
// PAYMENT (CRITICAL FOR CHECKOUT FORMS)
// =========================================================================
/** Full name on card */
ccName: 'cc-name',
/** First name on card */
ccGivenName: 'cc-given-name',
/** Last name on card */
ccFamilyName: 'cc-family-name',
/** Card number */
ccNumber: 'cc-number',
/** Expiry date (MM/YY or MM/YYYY) */
ccExp: 'cc-exp',
/** Expiry month */
ccExpMonth: 'cc-exp-month',
/** Expiry year */
ccExpYear: 'cc-exp-year',
/** Security code (CVV/CVC) */
ccCsc: 'cc-csc',
/** Card type (Visa, Mastercard, etc.) */
ccType: 'cc-type',
// =========================================================================
// ORGANIZATION
// =========================================================================
/** Company/Organization name */
organization: 'organization',
/** Job title */
organizationTitle: 'organization-title',
// =========================================================================
// DATES
// =========================================================================
/** Full birthday */
bday: 'bday',
/** Birthday day */
bdayDay: 'bday-day',
/** Birthday month */
bdayMonth: 'bday-month',
/** Birthday year */
bdayYear: 'bday-year',
// =========================================================================
// OTHER
// =========================================================================
/** Gender */
sex: 'sex',
/** Website URL */
url: 'url',
/** Photo URL */
photo: 'photo',
/** Preferred language */
language: 'language',
/** Instant messaging handle */
impp: 'impp',
// =========================================================================
// SPECIAL VALUES
// =========================================================================
/**
* Disable autofill - USE SPARINGLY
* Only for fields where autofill would be actively harmful
* (e.g., CAPTCHA, security questions)
*/
off: 'off',
/** Enable autofill (default browser behavior) */
on: 'on'
} as const;
export type AutocompleteValue = typeof AUTOCOMPLETE[keyof typeof AUTOCOMPLETE];
// =============================================================================
// AUTOCOMPLETE PRESETS
// =============================================================================
/**
* Pre-configured autocomplete sets for common form types
*/
export const AUTOCOMPLETE_PRESETS = {
/**
* Login form fields
*/
login: {
email: AUTOCOMPLETE.email,
username: AUTOCOMPLETE.username,
password: AUTOCOMPLETE.currentPassword
},
/**
* Registration form fields
*/
registration: {
email: AUTOCOMPLETE.email,
username: AUTOCOMPLETE.username,
password: AUTOCOMPLETE.newPassword,
confirmPassword: AUTOCOMPLETE.newPassword
},
/**
* Password reset fields
*/
passwordReset: {
password: AUTOCOMPLETE.newPassword,
confirmPassword: AUTOCOMPLETE.newPassword
},
/**
* Change password fields
*/
changePassword: {
currentPassword: AUTOCOMPLETE.currentPassword,
newPassword: AUTOCOMPLETE.newPassword,
confirmPassword: AUTOCOMPLETE.newPassword
},
/**
* 2FA/OTP fields
*/
twoFactor: {
code: AUTOCOMPLETE.oneTimeCode
},
/**
* Credit card fields
*/
creditCard: {
name: AUTOCOMPLETE.ccName,
number: AUTOCOMPLETE.ccNumber,
expiry: AUTOCOMPLETE.ccExp,
expiryMonth: AUTOCOMPLETE.ccExpMonth,
expiryYear: AUTOCOMPLETE.ccExpYear,
cvc: AUTOCOMPLETE.ccCsc
},
/**
* Shipping address fields
*/
shippingAddress: {
name: AUTOCOMPLETE.name,
street: AUTOCOMPLETE.addressLine1,
street2: AUTOCOMPLETE.addressLine2,
city: AUTOCOMPLETE.addressLevel2,
state: AUTOCOMPLETE.addressLevel1,
zip: AUTOCOMPLETE.postalCode,
country: AUTOCOMPLETE.country
},
/**
* Billing address fields
*/
billingAddress: {
name: AUTOCOMPLETE.name,
street: AUTOCOMPLETE.addressLine1,
street2: AUTOCOMPLETE.addressLine2,
city: AUTOCOMPLETE.addressLevel2,
state: AUTOCOMPLETE.addressLevel1,
zip: AUTOCOMPLETE.postalCode,
country: AUTOCOMPLETE.country
},
/**
* Contact form fields
*/
contact: {
name: AUTOCOMPLETE.name,
email: AUTOCOMPLETE.email,
phone: AUTOCOMPLETE.tel,
company: AUTOCOMPLETE.organization
},
/**
* Profile form fields
*/
profile: {
firstName: AUTOCOMPLETE.givenName,
lastName: AUTOCOMPLETE.familyName,
email: AUTOCOMPLETE.email,
phone: AUTOCOMPLETE.tel,
company: AUTOCOMPLETE.organization,
jobTitle: AUTOCOMPLETE.organizationTitle,
website: AUTOCOMPLETE.url
}
} as const;
// =============================================================================
// DEPRECATED/AVOID VALUES
// =============================================================================
/**
* Values to avoid or that have limited support
*/
export const DEPRECATED_AUTOCOMPLETE = {
/** Use 'name' instead */
fullName: 'full-name',
/** Use addressLine1 + addressLine2 instead */
streetAddress: 'street-address',
/** Inconsistent browser support */
transactionCurrency: 'transaction-currency',
transactionAmount: 'transaction-amount'
} as const;
// =============================================================================
// SECTION MODIFIERS
// =============================================================================
/**
* Section modifiers for forms with multiple address sets
*
* @example
* ```tsx
* // Shipping address
* <input autoComplete="shipping address-line1" />
*
* // Billing address
* <input autoComplete="billing address-line1" />
* ```
*/
export const AUTOCOMPLETE_SECTIONS = {
shipping: 'shipping',
billing: 'billing'
} as const;
/**
* Create a sectioned autocomplete value
*
* @example
* ```tsx
* const shippingStreet = withSection('shipping', AUTOCOMPLETE.addressLine1);
* // Returns: "shipping address-line1"
* ```
*/
export function withSection(
section: keyof typeof AUTOCOMPLETE_SECTIONS,
value: AutocompleteValue
): string {
return `${section} ${value}`;
}
// =============================================================================
// VALIDATION
// =============================================================================
/**
* Check if a value is a valid autocomplete attribute
*/
export function isValidAutocomplete(value: string): boolean {
const allValues = Object.values(AUTOCOMPLETE);
// Check direct match
if (allValues.includes(value as AutocompleteValue)) {
return true;
}
// Check sectioned value (e.g., "shipping address-line1")
const parts = value.split(' ');
if (parts.length === 2) {
const [section, base] = parts;
if (
Object.values(AUTOCOMPLETE_SECTIONS).includes(section as any) &&
allValues.includes(base as AutocompleteValue)
) {
return true;
}
}
return false;
}
// =============================================================================
// HELPER FUNCTIONS
// =============================================================================
/**
* Get the appropriate autocomplete value for a password field
* based on the form context
*/
export function getPasswordAutocomplete(
context: 'login' | 'registration' | 'reset' | 'change-current' | 'change-new'
): AutocompleteValue {
switch (context) {
case 'login':
case 'change-current':
return AUTOCOMPLETE.currentPassword;
case 'registration':
case 'reset':
case 'change-new':
return AUTOCOMPLETE.newPassword;
default:
return AUTOCOMPLETE.currentPassword;
}
}
/**
* Get autocomplete attribute with section prefix
* for forms with multiple addresses
*/
export function getAddressAutocomplete(
field: keyof typeof AUTOCOMPLETE_PRESETS.shippingAddress,
section?: 'shipping' | 'billing'
): string {
const baseValue = AUTOCOMPLETE_PRESETS.shippingAddress[field];
return section ? `${section} ${baseValue}` : baseValue;
}
Related skills
FAQ
Which autocomplete value goes on a registration password field?
new-password on both password fields, so the password manager offers to generate a new password.
Should paste be disabled on password fields?
No. The skill says to always allow paste and never add an onPaste handler that blocks it.