Files
tabler/preview/pages/password-strength.astro

169 lines
8.2 KiB
Plaintext

---
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import CaptureScript from '@shared/components/CaptureScript.astro'
import Card from '@ui/Card.astro'
import CardBody from '@ui/CardBody.astro'
import CardTitle from '@ui/CardTitle.astro'
import CardSubtitle from '@ui/CardSubtitle.astro'
import FormGroup from '@ui/FormGroup.astro'
import InputGroup from '@ui/InputGroup.astro'
import Strength from '@ui/Strength.astro'
import Badge from '@ui/Badge.astro'
import Button from '@ui/Button.astro'
import DocsLink from '@ui/DocsLink.astro'
---
<DefaultLayout title="Password strength" pageMenu="base.password-strength" description="A strength meter rates the password as the user types and fills a segmented bar, so weak passwords are visible before the form is sent.">
<DocsLink slot="page-header-actions" path="/ui/forms/strength" />
<div class="row row-cards">
<div class="col-md-6 col-lg-4">
<Card>
<CardBody>
<CardTitle>Basic</CardTitle>
<CardSubtitle>Add <code>data-bs-strength</code> to a <code>strength</code> element next to the field. A <code>strength-text</code> shows the label.</CardSubtitle>
<FormGroup label="Password" for="strength-basic" class="mb-0">
<input type="password" id="strength-basic" class="form-control" placeholder="Type a password…" autocomplete="new-password" />
<Strength />
</FormGroup>
</CardBody>
</Card>
</div>
<div class="col-md-6 col-lg-4">
<Card>
<CardBody>
<CardTitle>Rules until the first letter</CardTitle>
<CardSubtitle>Text written inside <code>strength-text</code> shows while the field is empty, so the password rules can stand there until a level takes over.</CardSubtitle>
<FormGroup label="Password" for="strength-hint" class="mb-0">
<input type="password" id="strength-hint" class="form-control" placeholder="Type a password…" autocomplete="new-password" />
<Strength>Use 8 to 20 characters, with letters and numbers.</Strength>
</FormGroup>
</CardBody>
</Card>
</div>
<div class="col-md-6 col-lg-4">
<Card>
<CardBody>
<CardTitle>Without a label</CardTitle>
<CardSubtitle>The <code>strength-text</code> is optional. Left out, the meter is the only feedback.</CardSubtitle>
<FormGroup label="Password" for="strength-bare" class="mb-0">
<input type="password" id="strength-bare" class="form-control" value="Abcdefgh1!" autocomplete="new-password" />
<Strength showText={false} />
</FormGroup>
</CardBody>
</Card>
</div>
<div class="col-md-6 col-lg-4">
<Card>
<CardBody>
<CardTitle>Number of segments</CardTitle>
<CardSubtitle>Segments fill in proportion, so a meter can have three, four or more of them.</CardSubtitle>
<FormGroup label="Three segments" for="strength-three">
<input type="password" id="strength-three" class="form-control" value="abcdefghijkl" autocomplete="new-password" />
<Strength segments={3} showText={false} ariaLabel="Password strength, three segments" />
</FormGroup>
<FormGroup label="Six segments" for="strength-six" class="mb-0">
<input type="password" id="strength-six" class="form-control" value="abcdefghijkl" autocomplete="new-password" />
<Strength segments={6} showText={false} ariaLabel="Password strength, six segments" />
</FormGroup>
</CardBody>
</Card>
</div>
<div class="col-md-6 col-lg-4">
<Card>
<CardBody>
<CardTitle>Own labels</CardTitle>
<CardSubtitle>Pass <code>data-bs-messages</code> as JSON to rename the levels.</CardSubtitle>
<FormGroup label="Password" for="strength-messages" class="mb-0">
<input type="password" id="strength-messages" class="form-control" value="Abcdefgh1!" autocomplete="new-password" />
<Strength messages={{ weak: 'Too easy', fair: 'Could be better', good: 'Solid', strong: 'Excellent' }} />
</FormGroup>
</CardBody>
</Card>
</div>
<div class="col-md-6 col-lg-4">
<Card>
<CardBody>
<CardTitle>Stricter scoring</CardTitle>
<CardSubtitle>Raise <code>data-bs-min-length</code> and <code>data-bs-thresholds</code> to demand more before a password counts as strong.</CardSubtitle>
<FormGroup label="Password" for="strength-strict" hint="The same password rates lower here than in the first card." class="mb-0">
<input type="password" id="strength-strict" class="form-control" value="Abcdefgh1!" autocomplete="new-password" />
<Strength minLength={12} thresholds={[3, 5, 7]} />
</FormGroup>
</CardBody>
</Card>
</div>
<div class="col-md-6 col-lg-4">
<Card>
<CardBody>
<CardTitle>Pointing at a field</CardTitle>
<CardSubtitle>With several password fields, name the one to rate with <code>data-bs-input</code>.</CardSubtitle>
<FormGroup label="New password" for="strength-new">
<InputGroup type="password" id="strength-new" placeholder="Enter a new password" autocomplete="new-password" appendButton={[{ icon: 'eye', description: 'Show password' }]} flat />
<Strength input="#strength-new" ariaLabel="New password strength" />
</FormGroup>
<FormGroup label="Confirm password" for="strength-confirm" class="mb-0">
<InputGroup type="password" id="strength-confirm" placeholder="Repeat the password" autocomplete="new-password" appendButton={[{ icon: 'eye', description: 'Show password' }]} flat />
</FormGroup>
</CardBody>
</Card>
</div>
<div class="col-md-6 col-lg-4">
<Card>
<CardBody>
<CardTitle>Reacting to the level</CardTitle>
<CardSubtitle>Every change of level fires <code>change.bs.strength</code> with the level and the score.</CardSubtitle>
<FormGroup label="Password" for="strength-event">
<input type="password" id="strength-event" class="form-control" placeholder="Type a password…" autocomplete="new-password" />
<Strength id="strength-event-meter" showText={false} />
</FormGroup>
<div class="d-flex align-items-center gap-2">
<Badge id="strength-event-level" color="secondary" light text="No password" />
<Button id="strength-event-submit" type="button" text="Create account" color="primary" size="sm" disabled />
</div>
<CaptureScript>
<!-- BEGIN SCRIPT OF PASSWORD STRENGTH -->
<script is:inline>
/*
Shows the level in a badge and only enables the button from "good" up.
The meter stays a hint: a real form validates on the server too.
*/
document.addEventListener('DOMContentLoaded', () => {
const meter = document.getElementById('strength-event-meter')
const badge = document.getElementById('strength-event-level')
const submit = document.getElementById('strength-event-submit')
const colors = { weak: 'red', fair: 'yellow', good: 'azure', strong: 'green' }
meter.addEventListener('change.bs.strength', (event) => {
const level = event.strength
badge.className = `badge bg-${level ? colors[level] : 'secondary'}-lt`
badge.textContent = level ? `${level} (${event.score} ${event.score === 1 ? 'point' : 'points'})` : 'No password'
submit.disabled = level !== 'good' && level !== 'strong'
})
})
</script>
<!-- END SCRIPT OF PASSWORD STRENGTH -->
</CaptureScript>
</CardBody>
</Card>
</div>
<div class="col-md-6 col-lg-4">
<Card>
<CardBody>
<CardTitle>Without a field</CardTitle>
<CardSubtitle>Without a password field in its parent and without <code>data-bs-input</code>, the meter stays empty.</CardSubtitle>
<Strength showText={false} />
</CardBody>
</Card>
</div>
</div>
</DefaultLayout>