Fix heading order, form markup, and a11y on preview pages (#3094)

This commit is contained in:
Bartosz-Do authored and GitHub committed 2026-09-18 16:33:14 +02:00
1 parent f1796f27ab
commit 0d39308ac2
60 files changed
+202 -170

No files matched your search

@@ -0,0 +1,6 @@
---
"@tabler/preview": patch
"@tabler/docs": patch
---
Fixed heading order, form `autocomplete` and accessible names on preview pages, `Alert`, `Button`, `Dropzone` and `Avatar`.
+2 -2
View File
@@ -10,7 +10,7 @@ import OtpInput from '@ui/OtpInput.astro'
<SingleLayout title="2-Step Verification">
<form class="card card-md" action="./" method="get" novalidate>
<div class="card-body">
<CardTitle class="text-center mb-4">Authenticate Your Account</CardTitle>
<CardTitle as="h1" class="text-center mb-4">Authenticate Your Account</CardTitle>
<p class="my-4 text-center">
Please confirm your account by entering the authorization code sent to <strong>+1 856-672-8552</strong>.
@@ -33,7 +33,7 @@ import OtpInput from '@ui/OtpInput.astro'
<FormFooter>
<ButtonList class="flex-nowrap">
<Button text="Cancel" block href="2-step-verification.html" />
<Button text="Verify" block color="primary" />
<Button type="submit" text="Verify" block color="primary" />
</ButtonList>
</FormFooter>
</div>
+2 -2
View File
@@ -10,7 +10,7 @@ import CardTitle from '@ui/CardTitle.astro'
<SingleLayout title="2-Step Verification">
<form class="card card-md" action="./2-step-verification-code.html" method="get" novalidate>
<div class="card-body">
<CardTitle class="text-center mb-4">2-Step Verification</CardTitle>
<CardTitle as="h1" class="text-center mb-4">2-Step Verification</CardTitle>
<FormGroup label="Country" for="verify-country">
<select class="form-select" id="verify-country" autocomplete="country-name">
@@ -21,7 +21,7 @@ import CardTitle from '@ui/CardTitle.astro'
<FormGroup label="Your Phone Number" for="verify-phone" class="mb-4">
<div class="input-group">
<span class="input-group-text">+1</span>
<input type="tel" class="form-control" id="verify-phone" placeholder="Enter phone number" autocomplete="tel-national" />
<input type="tel" class="form-control" id="verify-phone" placeholder="Enter phone number" autocomplete="tel" />
</div>
</FormGroup>
+8 -8
View File
@@ -79,12 +79,12 @@ function greetUser(name) {
<CardBody>
<div class="row">
<div class="col-md-6">
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<h4>Heading 4</h4>
<h5>Heading 5</h5>
<h6>Heading 6</h6>
<div class="h1">Heading 1</div>
<div class="h2">Heading 2</div>
<div class="h3">Heading 3</div>
<div class="h4">Heading 4</div>
<div class="h5">Heading 5</div>
<div class="h6">Heading 6</div>
</div>
<div class="col-md-6">
<p class="lead">This is a lead paragraph with larger text.</p>
@@ -238,7 +238,7 @@ function greetUser(name) {
<input type="email" class="form-control" id="all-elements-email-input" placeholder="Enter email" />
</FormGroup>
<FormGroup label="Password Input" for="all-elements-password-input">
<input type="password" class="form-control" id="all-elements-password-input" placeholder="Enter password" />
<input type="password" class="form-control" id="all-elements-password-input" placeholder="Enter password" autocomplete="current-password" />
</FormGroup>
<FormGroup label="Select Dropdown" for="select-demo-select">
<DataSelect id="demo-select" values={['Option 1', 'Option 2', 'Option 3']} />
@@ -377,7 +377,7 @@ function greetUser(name) {
<AvatarList>
<Avatar icon="user" />
<Avatar icon="star" color="warning" />
<Avatar placeholder="ST" status="success" />
<Avatar placeholder="ST" status="success" statusLabel="Online" />
</AvatarList>
</div>
</CardBody>
+1 -1
View File
@@ -3,6 +3,6 @@ import SingleLayout from '@shared/layouts/SingleLayout.astro'
import AuthLockCard from '@shared/components/cards/AuthLockCard.astro'
---
<SingleLayout title="Forgot password">
<SingleLayout title="Account locked">
<AuthLockCard />
</SingleLayout>
+6 -6
View File
@@ -25,12 +25,12 @@ const sizes = ['sm', 'md', 'lg']
<CardBody>
<CardTitle>In headings</CardTitle>
<CardSubtitle>A badge scales with the heading level it sits next to.</CardSubtitle>
<h1>Example heading <span class="badge">New</span></h1>
<h2>Example heading <span class="badge">New</span></h2>
<h3>Example heading <span class="badge">New</span></h3>
<h4>Example heading <span class="badge">New</span></h4>
<h5>Example heading <span class="badge">New</span></h5>
<h6>Example heading <span class="badge">New</span></h6>
<div class="h1">Example heading <span class="badge">New</span></div>
<div class="h2">Example heading <span class="badge">New</span></div>
<div class="h3">Example heading <span class="badge">New</span></div>
<div class="h4">Example heading <span class="badge">New</span></div>
<div class="h5">Example heading <span class="badge">New</span></div>
<div class="h6">Example heading <span class="badge">New</span></div>
</CardBody>
</Card>
</div>
+3 -3
View File
@@ -53,12 +53,12 @@ const messages = chats as Message[]
<div class="card-body scrollable"><Chat wide /></div>
<div class="card-footer">
<div class="input-group input-group-flat">
<input type="text" class="form-control" autocomplete="off" placeholder="Type message" />
<input type="text" class="form-control" autocomplete="off" placeholder="Type message" aria-label="Type message" />
<span class="input-group-text">
<a href="#" class="link-secondary" data-bs-toggle="tooltip" aria-label="Clear search" title="Clear search"> <Icon name="mood-smile" /> </a>
<a href="#" class="link-secondary" data-bs-toggle="tooltip" aria-label="Insert emoji" title="Insert emoji"> <Icon name="mood-smile" /> </a>
<a href="#" class="link-secondary ms-2" data-bs-toggle="tooltip" aria-label="Add notification" title="Add notification"> <Icon name="paperclip" /> </a>
<a href="#" class="link-secondary ms-2" data-bs-toggle="tooltip" aria-label="Attach file" title="Attach file"> <Icon name="paperclip" /> </a>
</span>
</div>
</div>
+1 -1
View File
@@ -135,7 +135,7 @@ const gradientColors = [...Object.keys(site.colors), 'inverted', 'white', 'trans
<CardBody>
<CardTitle>Gradient</CardTitle>
<CardSubtitle>Build a gradient from any two colors and preview it live.</CardSubtitle>
<form action="">
<form>
<div class="row g-4">
<div class="col">
<FormGroup label="From" for="colors-gradient-from" class="">
+1 -1
View File
@@ -22,7 +22,7 @@ const emailEntries = Object.entries(emails)
<div class="card-body">
<div class="row align-items-center">
<div class="col-10">
<h3 class="h1">Tabler Emails</h3>
<h2 class="h1">Tabler Emails</h2>
<Prose class="text-secondary fs-3">
{emailEntries.length} eye-catching, customizable and responsive email templates to improve your email communication. No coding skills needed.
</Prose>
+7 -7
View File
@@ -18,18 +18,18 @@ const categories = faq as { name: string; questions: { question: string }[] }[]
<h2 class="mb-3">
{ci + 1}. {category.name}
</h2>
<div id={`faq-${ci + 1}`} class="accordion accordion-tabs" role="tablist" aria-multiselectable="true">
<div id={`faq-${ci + 1}`} class="accordion accordion-tabs">
{category.questions.map((question, qi) => (
<div class="accordion-item">
<div class="accordion-header">
<button class={`accordion-button${qi === 0 ? '' : ' collapsed'}`} data-bs-toggle="collapse" data-bs-target={`#faq-${ci + 1}-${qi + 1}`} role="tab">
<h3 class="accordion-header">
<button id={`faq-btn-${ci + 1}-${qi + 1}`} class={`accordion-button${qi === 0 ? '' : ' collapsed'}`} type="button" data-bs-toggle="collapse" data-bs-target={`#faq-${ci + 1}-${qi + 1}`} aria-expanded={qi === 0 ? 'true' : 'false'} aria-controls={`faq-${ci + 1}-${qi + 1}`}>
{question.question}
<div class="accordion-button-toggle">
<span class="accordion-button-toggle">
<Icon name="chevron-down" />
</div>
</span>
</button>
</div>
<div id={`faq-${ci + 1}-${qi + 1}`} class={`accordion-collapse collapse${qi === 0 ? ' show' : ''}`} role="tabpanel" data-bs-parent={`#faq-${ci + 1}`}>
</h3>
<div id={`faq-${ci + 1}-${qi + 1}`} class={`accordion-collapse collapse${qi === 0 ? ' show' : ''}`} aria-labelledby={`faq-btn-${ci + 1}-${qi + 1}`} data-bs-parent={`#faq-${ci + 1}`}>
<div class="accordion-body pt-0">
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium alias dignissimos dolorum ea est eveniet, excepturi illum in iste iure maiores nemo recusandae rerum saepe sed, sunt totam! Explicabo, ipsa?</p>
+2 -2
View File
@@ -179,10 +179,10 @@ const rows = [
<input class="form-control" placeholder="your-email@domain.com" />
</FormGroup>
<FormGroup label="Password">
<input type="password" class="form-control" value="password" />
<input type="password" class="form-control" value="password" autocomplete="current-password" />
</FormGroup>
</CardBody>
<CardFooter class="text-end"><Button text="Save" color="primary" /></CardFooter>
<CardFooter class="text-end"><Button type="submit" text="Save" color="primary" /></CardFooter>
</Card>
</div>
</div>
+9 -9
View File
@@ -45,12 +45,12 @@ const countries = flags as { name: string }[]
</FormGroup>
</div>
<FormGroup label="Password" labelClass="visually-hidden" for="basic-password" class="">
<input type="password" placeholder="Password" class="form-control" id="basic-password" name="password" />
<input type="password" placeholder="Password" class="form-control" id="basic-password" name="password" autocomplete="new-password" />
</FormGroup>
<FormGroup label="Confirm Password" labelClass="visually-hidden" for="basic-password-confirm" class="">
<input type="password" placeholder="Confirm Password" class="form-control" id="basic-password-confirm" name="password_confirm" />
<input type="password" placeholder="Confirm Password" class="form-control" id="basic-password-confirm" name="password_confirm" autocomplete="new-password" />
</FormGroup>
<div><Button color="primary" block text="Submit" /></div>
<div><Button type="submit" color="primary" block text="Submit" /></div>
</form>
</CardBody>
</Card>
@@ -83,7 +83,7 @@ const countries = flags as { name: string }[]
<FormGroup label="Message" for="example-message" class="">
<textarea placeholder="Enter your message" rows="6" class="form-control" id="example-message" name="message"></textarea>
</FormGroup>
<div><Button color="primary" block text="Send Message" iconEnd="arrow-right" /></div>
<div><Button type="submit" color="primary" block text="Send Message" iconEnd="arrow-right" /></div>
</div>
</form>
</CardBody>
@@ -106,12 +106,12 @@ const countries = flags as { name: string }[]
<form class="space-y">
<div><InputIcon icon="user" placeholder="Username" prepend /></div>
<div><InputIcon icon="mail" placeholder="Email address" prepend type="email" /></div>
<div><InputIcon icon="lock" placeholder="Password" prepend type="password" /></div>
<div><InputIcon icon="lock" placeholder="Confirm Password" prepend type="password" /></div>
<div><InputIcon icon="lock" placeholder="Password" prepend type="password" autocomplete="new-password" /></div>
<div><InputIcon icon="lock" placeholder="Confirm Password" prepend type="password" autocomplete="new-password" /></div>
<div>
<div class="row align-items-center">
<div class="col"><Check title="Remember me" class="m-0" /></div>
<div class="col-auto"><Button color="primary" text="Create Account" iconEnd="arrow-right" /></div>
<div class="col-auto"><Button type="submit" color="primary" text="Create Account" iconEnd="arrow-right" /></div>
</div>
</div>
</form>
@@ -193,7 +193,7 @@ const countries = flags as { name: string }[]
</FormGroup>
<div><h4>Address</h4></div>
<FormGroup label="Street" for="example-form-street" class="">
<input type="text" id="example-form-street" class="form-control" autocomplete="street-address" />
<input type="text" id="example-form-street" class="form-control" autocomplete="address-line1" />
</FormGroup>
<div class="row row-cols-2 g-4">
<FormGroup label="City" for="example-form-city" class="">
@@ -224,7 +224,7 @@ const countries = flags as { name: string }[]
</div>
<ButtonList class="justify-content-end">
<Button text="Cancel" />
<Button color="primary" text="Save Changes" />
<Button type="submit" color="primary" text="Save Changes" />
</ButtonList>
</div>
</form>
+1 -1
View File
@@ -77,7 +77,7 @@ const salaries = ['$20K - $50K', '$50K - $100K', '> $100K']
</div>
<div class="mt-5">
<button class="btn btn-primary w-100"> Confirm changes </button>
<button type="submit" class="btn btn-primary w-100"> Confirm changes </button>
<a href="#" class="btn btn-link w-100"> Reset to defaults </a>
</div>
</form>
+7 -7
View File
@@ -13,23 +13,23 @@ import { site } from '@shared/lib/site'
<div class="col-lg-6">
<Card>
<CardBody>
<h4>Checked URL</h4>
<h2>Checked URL</h2>
<div>
<pre><code>GET <a class="text-reset" target="_blank" href={site.previewUrl}>{site.previewUrl}</a></code></pre>
</div>
<h4>Request Timing</h4>
<h2>Request Timing</h2>
<div>
<pre>Effective URL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a class="text-reset" target="_blank" href={site.previewUrl}>{site.previewUrl}</a><br />Redirect count&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0<br />Name lookup time&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3.4e-05<br />Connect time&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0.000521<br />Pre-transfer time&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0.0<br />Start-transfer time&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0.0<br />App connect time&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0.0<br />Redirect time&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0.0<br />Total time&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;28.000601<br />Response code&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0<br />Return keyword&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;operation_timedout</pre>
</div>
<h4>Response Headers</h4>
<h2>Response Headers</h2>
<div>
<pre>HTTP/1.1 200 Connection established</pre>
</div>
</CardBody>
<CardFooter>
<h4>Escalation</h4>
<h2>Escalation</h2>
<div>Entire team</div>
</CardFooter>
</Card>
@@ -37,7 +37,7 @@ import { site } from '@shared/lib/site'
<div class="col-lg-6">
<Card>
<CardBody>
<h4>Application Log</h4>
<h2>Application Log</h2>
<div>
<pre><code>2024-01-15 14:23:45 [INFO] Application started successfully
2024-01-15 14:23:46 [DEBUG] Database connection established
@@ -48,7 +48,7 @@ import { site } from '@shared/lib/site'
2024-01-15 14:23:51 [DEBUG] API request completed: endpoint=/api/users, duration=234ms</code></pre>
</div>
<h4>Log Levels</h4>
<h2>Log Levels</h2>
<BadgeList class="mb-2">
<Badge text="INFO" color="success" />
<Badge text="WARNING" color="warning" />
@@ -57,7 +57,7 @@ import { site } from '@shared/lib/site'
</BadgeList>
</CardBody>
<CardFooter>
<h4>Log Source</h4>
<h2>Log Source</h2>
<div>Application Server (prod-01)</div>
</CardFooter>
</Card>
+1 -1
View File
@@ -8,7 +8,7 @@ import Faq from '@shared/components/marketing/sections/Faq.astro'
<MarketingLayout title="Pricing">
<header class="hero">
<div class="container">
<h2 class="hero-title">Simple, transparent pricing</h2>
<h1 class="hero-title">Simple, transparent pricing</h1>
<p class="hero-description">Get early access to 100+ components and free updates every month. Make it yours today!</p>
</div>
</header>
+1 -1
View File
@@ -6,7 +6,7 @@ import Testimonials from '@shared/components/marketing/sections/Testimonials.ast
<MarketingLayout title="Testimonials">
<header class="hero">
<div class="container">
<h2 class="hero-title">Trusted by hundreds</h2>
<h1 class="hero-title">Trusted by hundreds</h1>
<p class="hero-description">Our Users send us bunch of smilies with our services, and we love them 😍</p>
</div>
</header>
+18 -18
View File
@@ -61,109 +61,109 @@ const cardClass = 'position-relative rounded d-block bg-surface-backdrop py-6 w-
<div class="col">
<div class="space-y-6">
<div>
<h3>Simple modal</h3>
<h2>Simple modal</h2>
<ModalInline class={cardClass} modalId="simple" show>
<SimpleModalContent />
</ModalInline>
</div>
<div>
<h3>Large modal</h3>
<h2>Large modal</h2>
<ModalInline class={cardClass} modalId="large" size="lg" show>
<LargeModalContent />
</ModalInline>
</div>
<div>
<h3>Small modal</h3>
<h2>Small modal</h2>
<ModalInline class={cardClass} modalId="small" size="sm" show>
<SmallModalContent />
</ModalInline>
</div>
<div>
<h3>Full width modal</h3>
<h2>Full width modal</h2>
<ModalInline class={cardClass} modalId="full-width" size="full-width" show>
<FullWidthModalContent />
</ModalInline>
</div>
<div>
<h3>Scrollable modal</h3>
<h2>Scrollable modal</h2>
<ModalInline class={cardClass} modalId="scrollable" scrollable style="max-height: 30rem" show>
<ScrollableModalContent />
</ModalInline>
</div>
<div>
<h3>Modal with form</h3>
<h2>Modal with form</h2>
<ModalInline class={cardClass} modalId="report" size="lg" show>
<ReportModalContent />
</ModalInline>
</div>
<div>
<h3>Success modal</h3>
<h2>Success modal</h2>
<ModalInline class={cardClass} modalId="success" size="sm" show>
<SuccessModalContent />
</ModalInline>
</div>
<div>
<h3>Danger modal</h3>
<h2>Danger modal</h2>
<ModalInline class={cardClass} modalId="danger" size="sm" show>
<DangerModalContent />
</ModalInline>
</div>
<div>
<h3>Modal with simple form</h3>
<h2>Modal with simple form</h2>
<ModalInline class={cardClass} modalId="team" show>
<TeamModalContent />
</ModalInline>
</div>
<div>
<h3>Modal with signature form</h3>
<h2>Modal with signature form</h2>
<ModalInline class={cardClass} modalId="signature" show>
<SignatureModalContent />
</ModalInline>
</div>
<div>
<h3>New email modal</h3>
<h2>New email modal</h2>
<ModalInline class={cardClass} modalId="new-email" show>
<NewEmailModalContent />
</ModalInline>
</div>
<div>
<h3>New event modal</h3>
<h2>New event modal</h2>
<ModalInline class={cardClass} modalId="new-event" show>
<NewEventModalContent />
</ModalInline>
</div>
<div>
<h3>New task modal</h3>
<h2>New task modal</h2>
<ModalInline class={cardClass} modalId="new-task" show>
<NewTaskModalContent />
</ModalInline>
</div>
<div>
<h3>Edit profile modal</h3>
<h2>Edit profile modal</h2>
<ModalInline class={cardClass} modalId="edit-profile" size="lg" show>
<EditProfileModalContent />
</ModalInline>
</div>
<div>
<h3>Confirm delete modal</h3>
<h2>Confirm delete modal</h2>
<ModalInline class={cardClass} modalId="confirm-delete" size="sm" show>
<ConfirmDeleteModalContent />
</ModalInline>
</div>
<div>
<h3>Change password modal</h3>
<h2>Change password modal</h2>
<ModalInline class={cardClass} modalId="change-password" show>
<ChangePasswordModalContent />
</ModalInline>
</div>
<div>
<h3>Add task modal</h3>
<h2>Add task modal</h2>
<ModalInline class={cardClass} modalId="add-task" show>
<AddTaskModalContent />
</ModalInline>
</div>
<div id="modal-native">
<h3>Native dialog</h3>
<h2>Native dialog</h2>
<p class="text-secondary">
A native <code>&lt;dialog&gt;</code> opened with <code>showModal()</code>. The browser paints the backdrop and Tabler styles it to match the one used by modals, with
<code>.modal-blur</code> blurring the page behind it. Buttons inside <code>&lt;form method="dialog"&gt;</code> close the dialog without any script. The panel uses the card classes on a child element, because the modal classes read CSS variables set on <code>.modal</code>, and a <code>display</code> value
+1 -1
View File
@@ -12,7 +12,7 @@ const topTrackIds = [8, 9, 10, 11, 12, 13]
<TracksList />
</div>
<div class="col-lg-4">
<h3 class="mb-3">Top tracks</h3>
<h2 class="mb-3">Top tracks</h2>
<div class="row row-cards">
{
+1 -1
View File
@@ -22,7 +22,7 @@ import Icon from '@ui/Icon.astro'
<div class="mb-3 text-center">
<Avatar person={personById(1)} size="xl" class="avatar-cover rounded-circle mb-3" />
<div class="mb-4">
<h2 class="h2">Front-End Learning</h2>
<h1 class="h2">Front-End Learning</h1>
<div class="text-secondary">Learn to build web apps with HTML & CSS. Get started quickly with included templates.</div>
</div>
</div>
+8 -8
View File
@@ -13,7 +13,7 @@ import DocsLink from '@ui/DocsLink.astro'
<div class="card card-lg">
<div class="card-body">
<Prose>
<h1>Getting started with documentation <span class="badge">New</span></h1>
<h2>Getting started with documentation <span class="badge">New</span></h2>
<div class="d-flex align-items-center text-secondary mb-4">
<Avatar placeholder="PK" size="sm" class="me-2" />
Written by Paweł Kuna · 6 min read
@@ -38,7 +38,7 @@ import DocsLink from '@ui/DocsLink.astro'
</p>
</div>
<h2>A quick glossary</h2>
<h3>A quick glossary</h3>
<dl>
<dt>Prose</dt>
<dd>Long-form, readable content — articles, changelogs, help center entries.</dd>
@@ -48,13 +48,13 @@ import DocsLink from '@ui/DocsLink.astro'
<dd>A shared reference so every writer on the team formats things the same way.</dd>
</dl>
<h2>Adding code examples</h2>
<h3>Adding code examples</h3>
<p>
Inline code looks like <code>console.log("Hello")</code> and uses monospace styling. For anything longer, drop it into a code block, and mention shortcuts with <kbd>Ctrl</kbd> + <kbd>C</kbd> style keys:
</p>
<pre><code>{`function add(a, b) {\n return a + b;\n}`}</code></pre>
<h2>Structuring steps and points</h2>
<h3>Structuring steps and points</h3>
<p>Use an ordered list to walk through a process:</p>
<ol>
<li>Start with the most important information.</li>
@@ -68,7 +68,7 @@ import DocsLink from '@ui/DocsLink.astro'
<li>Avoid overly long items.</li>
</ul>
<h3>Nesting related items</h3>
<h4>Nesting related items</h4>
<p>Lists can nest, with indentation and spacing handled automatically:</p>
<ul>
<li>
@@ -88,7 +88,7 @@ import DocsLink from '@ui/DocsLink.astro'
<li>Sharing</li>
</ul>
<h3>A visual checklist</h3>
<h4>A visual checklist</h4>
<p>For a status readers can scan at a glance, drop in the steps component instead of a plain list:</p>
<ul class="steps steps-vertical steps-counter my-4">
<li class="step-item">Draft</li>
@@ -99,14 +99,14 @@ import DocsLink from '@ui/DocsLink.astro'
<hr />
<h2>Supporting images</h2>
<h3>Supporting images</h3>
<p>Images should support the text and provide useful context, not just decorate the page.</p>
<figure>
<img src="./static/photos/cup-of-coffee-and-an-open-book.jpg" alt="Open book and coffee" />
<figcaption class="text-secondary small mt-2">A quiet spot makes for better writing sessions.</figcaption>
</figure>
<h2>Comparing data in tables</h2>
<h3>Comparing data in tables</h3>
<p>Tables work best for comparing related data points, like votes on a proposal:</p>
<table>
<thead>
+1
View File
@@ -45,6 +45,7 @@ import { site } from '@shared/lib/site'
</style>
<main id="content" class="page page-center align-items-center">
<h1 class="visually-hidden">Screenshot</h1>
<div class="screenshot d-flex flex-column justify-content-center align-items-center px-12">
<div class="screenshot-logo">
<Logo gray />
+2 -2
View File
@@ -67,7 +67,7 @@ const articles: [string, string[]][] = [
<div class="row g-5">
<div class="col-sm-2">
<div class="sticky-top">
<h3>Menu</h3>
<h2>Menu</h2>
<nav class="nav nav-vertical nav-pills" id="pills">
{
articles.map(([header]) => (
@@ -85,7 +85,7 @@ const articles: [string, string[]][] = [
{
articles.map(([header, paragraphs]) => (
<Fragment>
<h3 id={`pills-${slug(header)}`}>{header}</h3>
<h2 id={`pills-${slug(header)}`}>{header}</h2>
{paragraphs.map((paragraph, index) => (
<p class={index === paragraphs.length - 1 ? 'mb-6' : undefined}>{paragraph}</p>
))}
+1 -1
View File
@@ -45,7 +45,7 @@ const person = requireIndex(people, 0)
<div>
<div class="row g-2">
<FormGroup label="Email" for="email" labelClass="visually-hidden" class="col-auto">
<input type="text" class="form-control w-auto" id="email" name="email" value={person.email} />
<input type="email" class="form-control w-auto" id="email" name="email" value={person.email} autocomplete="email" />
</FormGroup>
<div class="col-auto"><Button text="Change" /></div>
</div>
+1 -1
View File
@@ -15,7 +15,7 @@ import { requireIndex } from '@shared/lib/array'
<Logo />
</div>
<h2 class="h3 text-center mb-3">Login to your account</h2>
<h1 class="h3 text-center mb-3">Login to your account</h1>
<SignInForm />
+1 -1
View File
@@ -7,7 +7,7 @@ const siteEmail = 'support@tabler.io'
<SingleLayout title="Sign in link">
<div class="text-center">
<div class="my-5">
<h2 class="h1">Check your inbox</h2>
<h1>Check your inbox</h1>
<p class="fs-3 text-secondary">
We've sent you a magic link to <strong>{siteEmail}</strong>.<br />
+1 -1
View File
@@ -66,7 +66,7 @@ document.querySelector("#signature-advanced-png").addEventListener("click", func
<CardBody>
<CardTitle>Confirm transfer</CardTitle>
<CardSubtitle>Please confirm the transfer of funds by signing below.</CardSubtitle>
<form action="">
<form>
<FormGroup label="First name" required for="signature-first-name">
<input type="text" class="form-control" id="signature-first-name" name="first_name" />
</FormGroup>
+1 -1
View File
@@ -7,7 +7,7 @@ import Prose from '@ui/Prose.astro'
<SingleLayout title="Terms of service" containerSize="narrow">
<div class="card card-md">
<div class="card-body">
<CardTitle>Terms of service</CardTitle>
<CardTitle as="h1">Terms of service</CardTitle>
<Prose>
<p>
We (the folks at Tabler) run a website hosting platform called <a href="https://tabler.io">tabler.io</a> and would love for you to use it. Tabler.io's basic service is free, and we offer paid upgrades for advanced features. Our service is designed to give you as much control and ownership over what goes on your
+1 -1
View File
@@ -11,7 +11,7 @@ import DocsLink from '@ui/DocsLink.astro'
<div class="card card-lg">
<div class="card-body">
<Prose>
<h1>Brewing better coffee at home</h1>
<div class="h1">Brewing better coffee at home</div>
<p class="lead">Good coffee isn't about expensive gear — it's about <mark>consistency</mark>. Get the ratio, the grind, and the water temperature right, and almost any method will taste better.</p>
<figure>
+2 -2
View File
@@ -11,7 +11,7 @@ const person = requireIndex(people, 0)
<form class="card card-md" action="./" method="get" novalidate>
<div class="card-body text-center">
<div class="mb-4">
<CardTitle>Account Locked</CardTitle>
<CardTitle as="h1">Account Locked</CardTitle>
<p class="text-secondary">Please enter your password to unlock your account</p>
</div>
@@ -26,7 +26,7 @@ const person = requireIndex(people, 0)
</div>
<div>
<Button color="primary" block icon="lock-open" text="Unlock" />
<Button type="submit" color="primary" block icon="lock-open" text="Unlock" />
</div>
</div>
</form>
@@ -28,7 +28,7 @@ import OtpInput from '@ui/OtpInput.astro'
<FormFooter>
<ButtonList class="flex-nowrap">
<Button text="Cancel" block href="#" />
<Button text="Verify" block color="primary" />
<Button type="submit" text="Verify" block color="primary" />
</ButtonList>
</FormFooter>
</div>
+1 -1
View File
@@ -38,7 +38,7 @@ const years = Array.from({ length: 11 }, (_, i) => 2020 + i)
<div class="col">
<div class="mb-3">
<label class="form-label" for="credit-card-cvv">CVV</label>
<input type="number" id="credit-card-cvv" class="form-control" autocomplete="cc-csc" />
<input type="text" inputmode="numeric" id="credit-card-cvv" class="form-control" autocomplete="cc-csc" />
</div>
</div>
</div>
@@ -7,7 +7,7 @@ import CardTitle from '@ui/CardTitle.astro'
<form class="card card-md" action="./" method="get" novalidate>
<div class="card-body">
<CardTitle class="text-center mb-4">Forgot password</CardTitle>
<CardTitle as="h1" class="text-center mb-4">Forgot password</CardTitle>
<p class="text-secondary mb-4">Enter your email address and your password will be reset and emailed to you.</p>
@@ -15,7 +15,7 @@ import CardTitle from '@ui/CardTitle.astro'
<input type="email" class="form-control" placeholder="Enter email" id="forgot-email" autocomplete="email" required />
</FormGroup>
<FormFooter>
<Button text="Send me new password" block color="primary" icon="mail" />
<Button type="submit" text="Send me new password" block color="primary" icon="mail" />
</FormFooter>
</div>
</form>
+1 -1
View File
@@ -5,7 +5,7 @@ import Button from '@ui/Button.astro'
<div class="card card-gradient card-gradient-rainbow">
<div class="card-body text-center p-5">
<div class="display-5 lh-1 mb-2">🍾 🎉</div>
<h1>Happy Birthday, Andrew!</h1>
<h2 class="h1">Happy Birthday, Andrew!</h2>
<p class="text-secondary">We truly hope your day is brimming with joy, laughter, and countless moments that bring a smile to your face!</p>
<p class="text-secondary">To celebrate your special day, here's a discount code just for you: <strong class="text-body">NWYR20</strong>. Enjoy <strong class="text-body">20% off</strong> your next purchase!</p>
<div class="mt-5">
+1 -1
View File
@@ -16,7 +16,7 @@ const { class: className } = Astro.props
<div class="card-body">
<div class="row align-items-center">
<div class="col-10">
<h3 class="h1">Tabler Icons</h3>
<h2 class="h1">Tabler Icons</h2>
<Prose>
All icons come from the Tabler Icons set and are MIT-licensed. Visit
<a href={site.icons.link} target="_blank" rel="noopener">Tabler Icons Website</a>, download any of the {site.iconsCount} icons in SVG, PNG or&nbsp;React and use them in your favourite design tools.
+1 -1
View File
@@ -25,7 +25,7 @@
</div>
<div class="col-12 my-5">
<h1>Invoice INV/001/15</h1>
<h2 class="h1">Invoice INV/001/15</h2>
</div>
</div>
+2 -2
View File
@@ -76,12 +76,12 @@ const countryNames = Object.fromEntries((countries as { code: string; name: stri
<td>{invoice.price}</td>
<td class="text-end">
<span class="dropdown">
<div class="dropdown">
<button class="btn dropdown-toggle align-text-top" data-bs-boundary="viewport" data-bs-toggle="dropdown">
Actions
</button>
<DropdownMenu right={true} />
</span>
</div>
</td>
</tr>
))
+4 -6
View File
@@ -9,12 +9,10 @@ import InputGroup from '@ui/InputGroup.astro'
<input type="email" class="form-control" placeholder="your@email.com" id="signin-email" autocomplete="email" required />
</FormGroup>
<div class="mb-2">
<label class="form-label" for="signin-password">
Password
<span class="form-label-description">
<a href="./forgot-password.html">I forgot password</a>
</span>
</label>
<div class="d-flex">
<label class="form-label" for="signin-password">Password</label>
<a href="./forgot-password.html" class="form-label-description ms-auto">I forgot password</a>
</div>
<InputGroup type="password" placeholder="Your password" flat id="signin-password" autocomplete="current-password" required appendButton={[{ icon: 'eye', description: 'Show password' }]} />
</div>
<div class="mb-2">
+5 -6
View File
@@ -8,7 +8,7 @@ import CardTitle from '@ui/CardTitle.astro'
<form class="card card-md" action="./" method="get" novalidate>
<div class="card-body">
<CardTitle class="text-center mb-4">Create new account</CardTitle>
<CardTitle as="h1" class="text-center mb-4">Create new account</CardTitle>
<FormGroup label="Name" for="signup-name">
<input type="text" class="form-control" placeholder="Enter name" id="signup-name" autocomplete="name" required />
@@ -20,11 +20,10 @@ import CardTitle from '@ui/CardTitle.astro'
<InputGroup type="password" appendButton={[{ icon: 'eye', description: 'Show password' }]} flat placeholder="Password" id="signup-password" autocomplete="new-password" required />
<Strength />
</FormGroup>
<div class="mb-3">
<label class="form-check">
<input type="checkbox" class="form-check-input" />
<span class="form-check-label">Agree the <a href="./terms-of-service.html">terms and policy</a>.</span>
</label>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="signup-terms" required />
<label class="form-check-label d-inline" for="signup-terms">Agree the</label>
<a href="./terms-of-service.html">terms and policy</a>.
</div>
<FormFooter>
+4 -4
View File
@@ -76,17 +76,17 @@ const paneClass = `tab-pane${animation ? ' fade' : ''}`
<div class="card-body">
<div class="tab-content">
<div class={`${paneClass} active show`} id={`tabs-home-${id}`} role="tabpanel" aria-labelledby={`tabs-home-${id}-tab`}>
<h4>Home tab</h4>
<h2>Home tab</h2>
<div>Cursus turpis vestibulum, dui in pharetra vulputate id sed non turpis ultricies fringilla at sed facilisis lacus pellentesque purus nibh</div>
</div>
<div class={paneClass} id={`tabs-profile-${id}`} role="tabpanel" aria-labelledby={`tabs-profile-${id}-tab`}>
<h4>Profile tab</h4>
<h2>Profile tab</h2>
<div>Fringilla egestas nunc quis tellus diam rhoncus ultricies tristique enim at diam, sem nunc amet, pellentesque id egestas velit sed</div>
</div>
{
settings && (
<div class={paneClass} id={`tabs-settings-${id}`} role="tabpanel" aria-labelledby={`tabs-settings-${id}-tab`}>
<h4>Settings tab</h4>
<h2>Settings tab</h2>
<div>Donec ac vitae diam amet vel leo egestas consequat rhoncus in luctus amet, facilisi sit mauris accumsan nibh habitant senectus</div>
</div>
)
@@ -94,7 +94,7 @@ const paneClass = `tab-pane${animation ? ' fade' : ''}`
{
activity && (
<div class={paneClass} id={`tabs-activity-${id}`} role="tabpanel" aria-labelledby={`tabs-activity-${id}-tab`}>
<h4>Activity tab</h4>
<h2>Activity tab</h2>
<div>Donec ac vitae diam amet vel leo egestas consequat rhoncus in luctus amet, facilisi sit mauris accumsan nibh habitant senectus</div>
</div>
)
+4 -4
View File
@@ -25,14 +25,14 @@ const tasks = crmDashboard.tasks_due
<ListGroup flush hoverable>
{
tasks.items.map((item) => (
<ListGroupItem as="label">
tasks.items.map((item, index) => (
<ListGroupItem>
<div class="row align-items-center g-2">
<div class="col-auto">
<input type="checkbox" class="form-check-input m-0" />
<input type="checkbox" class="form-check-input m-0" id={`task-due-${index}`} />
</div>
<div class="col">
<div>{item.text}</div>
<label for={`task-due-${index}`}>{item.text}</label>
</div>
<div class="col-auto d-flex align-items-center gap-2">
<span class={`legend-dot bg-${item.color}`} />
+1 -1
View File
@@ -5,7 +5,7 @@ import Button from '@ui/Button.astro'
<div class="card card-gradient card-gradient-gold">
<div class="card-body text-center p-5">
<div class="display-3 lh-1 mb-2">🏆</div>
<h1>You are winner!</h1>
<h2 class="h1">You are winner!</h2>
<p class="text-secondary">You've been selected as our lucky winner for completing <strong class="text-body">100 orders</strong> this month! Click below to claim your exclusive prize and enjoy the benefits!</p>
<div class="mt-5">
<Button text="Claim Your Prize" icon="gift" color="primary" />
+1 -1
View File
@@ -30,7 +30,7 @@ const idSuffix = horizontal ? '-horizontal' : ''
<div class:list={['mb-3', horizontal && 'row']}>
<label class={`${labelClass} required`} for={`form-layout-password${idSuffix}`}>Password</label>
<div class={horizontal ? 'col' : undefined}>
<input type="password" id={`form-layout-password${idSuffix}`} class="form-control" aria-describedby={`form-layout-password-hint${idSuffix}`} aria-required="true" placeholder="Password" />
<input type="password" id={`form-layout-password${idSuffix}`} class="form-control" aria-describedby={`form-layout-password-hint${idSuffix}`} aria-required="true" placeholder="Password" autocomplete="new-password" />
<FormText id={`form-layout-password-hint${idSuffix}`}> Your password must be 8-20 characters long, contain letters and numbers, and must not contain spaces, special characters, or emoji. </FormText>
</div>
</div>
+1 -1
View File
@@ -85,7 +85,7 @@ import FormGroup from '@ui/FormGroup.astro'
<div class="mt-4">
<ButtonList>
<Button text="Submit" color="primary" />
<Button type="submit" text="Submit" color="primary" />
<Button text="Cancel" />
</ButtonList>
</div>
+4 -4
View File
@@ -34,16 +34,16 @@ const accordionClasses = ['accordion', ...types.map((t) => `accordion-${t}`)].jo
<h2 class="accordion-header">
<button id={`accordion-button-${index}-${id}`} class={`accordion-button${isFirst ? '' : ' collapsed'}`} type="button" data-bs-toggle="collapse" data-bs-target={`#collapse-${index}-${id}`} aria-expanded={isFirst ? 'true' : 'false'} aria-controls={`collapse-${index}-${id}`}>
{showIcon && (
<div class="accordion-button-icon">
<span class="accordion-button-icon">
<Icon name="link" />
</div>
</span>
)}
{question.question}
<div class={`accordion-button-toggle${hasToggleIcon ? ' accordion-button-toggle-plus' : ''}`}>
<span class={`accordion-button-toggle${hasToggleIcon ? ' accordion-button-toggle-plus' : ''}`}>
<Icon name={resolvedToggleIcon} />
</div>
</span>
</button>
</h2>
<div id={`collapse-${index}-${id}`} class={`accordion-collapse collapse${isFirst ? ' show' : ''}`} data-bs-parent={`#accordion-${id}`} role="region" aria-labelledby={`accordion-button-${index}-${id}`}>
+10 -2
View File
@@ -18,7 +18,7 @@ const states = (selects as { states: { options: Record<string, { name: string; s
</FormGroup>
<FormGroup label="Password" for="fe1-password">
<input type="text" class="form-control" id="fe1-password" name="example-password-input" placeholder="Input placeholder" />
<input type="password" class="form-control" id="fe1-password" name="example-password-input" placeholder="Input placeholder" autocomplete="current-password" />
</FormGroup>
<FormGroup label="Disabled" for="fe1-disabled">
@@ -139,7 +139,15 @@ const states = (selects as { states: { options: Record<string, { name: string; s
<input type="text" class="form-control" id="fe1-help-icon-input" placeholder="Search for…" />
</div>
<div class="col-auto align-self-center">
<span class="form-help" data-bs-toggle="popover" data-bs-placement="top" data-bs-content="<p>ZIP Code must be US or CDN format. You can use an extended ZIP+4 code to determine address more accurately.</p><p class='mb-0'><a href='#'>USP ZIP codes lookup tools</a></p>" data-bs-html="true">?</span>
<button
type="button"
class="form-help"
data-bs-toggle="popover"
data-bs-placement="top"
data-bs-content="<p>ZIP Code must be US or CDN format. You can use an extended ZIP+4 code to determine address more accurately.</p><p class='mb-0'><a href='#'>USP ZIP codes lookup tools</a></p>"
data-bs-html="true"
aria-label="Help">?</button
>
</div>
</div>
</FormGroup>
+2 -2
View File
@@ -68,7 +68,7 @@ import InputGroup from '@ui/InputGroup.astro'
</FormGroup>
<FormGroup label="Input with appended link" for="fe2-appended-link">
<InputGroup type="password" id="fe2-appended-link" value="ultrastrongpassword" flat appendButton={[{ icon: 'eye', description: 'Show password' }]} />
<InputGroup type="password" id="fe2-appended-link" value="ultrastrongpassword" flat autocomplete="current-password" appendButton={[{ icon: 'eye', description: 'Show password' }]} />
</FormGroup>
<FormGroup label="Input with appended kbd" for="fe2-appended-kbd">
@@ -103,7 +103,7 @@ import InputGroup from '@ui/InputGroup.astro'
<label for="floating-input">Email address</label>
</div>
<div class="form-floating mb-3">
<input type="password" class="form-control" id="floating-password" value="Password" autocomplete="off" />
<input type="password" class="form-control" id="floating-password" value="Password" autocomplete="current-password" />
<label for="floating-password">Password</label>
</div>
<div class="form-floating">
+15 -15
View File
@@ -236,13 +236,13 @@ import Avatar from '@ui/Avatar.astro'
<legend class="visually-hidden">Buttons group</legend>
<ButtonGroup class="w-100">
<input type="radio" class="btn-check" name="btn-radio-basic" id="btn-radio-basic-1" autocomplete="off" checked />
<label for="btn-radio-basic-1" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">1 min</label>
<label for="btn-radio-basic-1" class="btn">1 min</label>
<input type="radio" class="btn-check" name="btn-radio-basic" id="btn-radio-basic-2" autocomplete="off" />
<label for="btn-radio-basic-2" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">5 min</label>
<label for="btn-radio-basic-2" class="btn">5 min</label>
<input type="radio" class="btn-check" name="btn-radio-basic" id="btn-radio-basic-3" autocomplete="off" />
<label for="btn-radio-basic-3" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">10 min</label>
<label for="btn-radio-basic-3" class="btn">10 min</label>
<input type="radio" class="btn-check" name="btn-radio-basic" id="btn-radio-basic-4" autocomplete="off" />
<label for="btn-radio-basic-4" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">30 min</label>
<label for="btn-radio-basic-4" class="btn">30 min</label>
</ButtonGroup>
</fieldset>
</FormGroup>
@@ -252,9 +252,9 @@ import Avatar from '@ui/Avatar.astro'
<legend class="visually-hidden">Buttons group with dropdown</legend>
<ButtonGroup class="w-100">
<input type="radio" class="btn-check" name="btn-radio-dropdown" id="btn-radio-dropdown-1" autocomplete="off" checked />
<label for="btn-radio-dropdown-1" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">Option 1</label>
<label for="btn-radio-dropdown-1" class="btn">Option 1</label>
<input type="radio" class="btn-check" name="btn-radio-dropdown" id="btn-radio-dropdown-2" autocomplete="off" />
<label for="btn-radio-dropdown-2" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">Option 2</label>
<label for="btn-radio-dropdown-2" class="btn">Option 2</label>
<ButtonGroup>
<button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Other </button>
<div class="dropdown-menu">
@@ -277,15 +277,15 @@ import Avatar from '@ui/Avatar.astro'
<legend class="visually-hidden">Vertical buttons group</legend>
<ButtonGroup vertical={true} class="w-100">
<input type="radio" class="btn-check" name="btn-radio-vertical" id="btn-radio-vertical-1" autocomplete="off" checked />
<label for="btn-radio-vertical-1" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">Button 1</label>
<label for="btn-radio-vertical-1" class="btn">Button 1</label>
<input type="radio" class="btn-check" name="btn-radio-vertical" id="btn-radio-vertical-2" autocomplete="off" />
<label for="btn-radio-vertical-2" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">Button 2</label>
<label for="btn-radio-vertical-2" class="btn">Button 2</label>
<input type="radio" class="btn-check" name="btn-radio-vertical" id="btn-radio-vertical-3" autocomplete="off" />
<label for="btn-radio-vertical-3" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">Button 3</label>
<label for="btn-radio-vertical-3" class="btn">Button 3</label>
<input type="radio" class="btn-check" name="btn-radio-vertical" id="btn-radio-vertical-4" autocomplete="off" />
<label for="btn-radio-vertical-4" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">Button 4</label>
<label for="btn-radio-vertical-4" class="btn">Button 4</label>
<input type="radio" class="btn-check" name="btn-radio-vertical" id="btn-radio-vertical-5" autocomplete="off" />
<label for="btn-radio-vertical-5" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">Button 5</label>
<label for="btn-radio-vertical-5" class="btn">Button 5</label>
</ButtonGroup>
</fieldset>
</FormGroup>
@@ -296,13 +296,13 @@ import Avatar from '@ui/Avatar.astro'
<legend class="visually-hidden">Vertical with dropdown</legend>
<ButtonGroup vertical={true} class="w-100">
<input type="radio" class="btn-check" name="btn-radio-vertical-dropdown" id="btn-radio-vertical-dropdown-1" autocomplete="off" checked />
<label for="btn-radio-vertical-dropdown-1" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">Button 1</label>
<label for="btn-radio-vertical-dropdown-1" class="btn">Button 1</label>
<input type="radio" class="btn-check" name="btn-radio-vertical-dropdown" id="btn-radio-vertical-dropdown-2" autocomplete="off" />
<label for="btn-radio-vertical-dropdown-2" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">Button 2</label>
<label for="btn-radio-vertical-dropdown-2" class="btn">Button 2</label>
<input type="radio" class="btn-check" name="btn-radio-vertical-dropdown" id="btn-radio-vertical-dropdown-3" autocomplete="off" />
<label for="btn-radio-vertical-dropdown-3" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">Button 3</label>
<label for="btn-radio-vertical-dropdown-3" class="btn">Button 3</label>
<input type="radio" class="btn-check" name="btn-radio-vertical-dropdown" id="btn-radio-vertical-dropdown-4" autocomplete="off" />
<label for="btn-radio-vertical-dropdown-4" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">Button 4</label>
<label for="btn-radio-vertical-dropdown-4" class="btn">Button 4</label>
<ButtonGroup>
<button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Other </button>
<div class="dropdown-menu">
@@ -10,7 +10,7 @@ import Signature from '@ui/Signature.astro'
<div class="modal-body">
<CardTitle id="modal-signature-title">Confirm transfer</CardTitle>
<CardSubtitle>Please confirm the transfer of funds by signing below.</CardSubtitle>
<form action="">
<form>
<FormGroup label="Signature" required associate={false}>
<div class="position-relative user-select-none">
<Signature id="default" clear width={684} height={400} />
@@ -21,6 +21,6 @@ import Signature from '@ui/Signature.astro'
</div>
<div class="modal-footer">
<button type="button" class="btn">Cancel</button>
<button type="button" class="btn btn-primary ms-auto">Confirm transfer</button>
<button type="button" class="btn" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary ms-auto" data-bs-dismiss="modal">Confirm transfer</button>
</div>
+1
View File
@@ -120,6 +120,7 @@ const headerClass = [
<NavbarMenu sample={sample} hideIcons={hideIcons} pageMenu={pageMenu} />
</nav>
<!-- END NAVBAR MENU -->
<NavbarSearch class="my-2 my-md-0 flex-grow-1 flex-md-grow-0 order-first order-md-last" />
</div>
)}
</div>
+1 -1
View File
@@ -12,7 +12,7 @@ const { class: className } = Astro.props
<!-- BEGIN NAVBAR SEARCH -->
<div class={className}>
<form action="./" method="get" autocomplete="off" novalidate role="search">
<InputIcon prepend ariaLabel="Search in website" />
<InputIcon prepend name="q" ariaLabel="Search in website" />
</form>
</div>
<!-- END NAVBAR SEARCH -->
+2 -2
View File
@@ -19,10 +19,10 @@ const person = requireIndex(people, personId - 1)
<li class="nav-item dropup">
<a href="#" class="nav-link" data-bs-toggle="dropdown" aria-label="Open user menu">
<Avatar person={personById(personId)} size="sm" />
<span class="nav-link-title">
<div class="nav-link-title">
{person.full_name}
<div class="small text-secondary">{person.job_title}</div>
</span>
</div>
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="./profile.html"><Icon name="user" class="dropdown-item-icon" /> Profile</a>
+2 -2
View File
@@ -61,7 +61,7 @@ const tags = ['business', 'evening', 'leisure', 'party']
<Subheader class="mb-2">Shipping</Subheader>
<div>
<select name="" class="form-select">
<select name="shipping-country" class="form-select">
<option>United Kingdom</option>
<option>USA</option>
<option>Germany</option>
@@ -71,7 +71,7 @@ const tags = ['business', 'evening', 'leisure', 'party']
</div>
<div class="mt-5">
<Button text="Confirm changes" color="primary" block element="button" />
<Button type="submit" text="Confirm changes" color="primary" block element="button" />
<Button text="Reset to defaults" color="link" block />
</div>
</form>
+5 -2
View File
@@ -1,4 +1,5 @@
---
import type { HTMLTag } from 'astro/types'
import Icon from './Icon.astro'
/** alert-{color} — matches defaultIcons below */
@@ -11,6 +12,8 @@ interface Props {
showClose?: boolean
class?: string
title?: string
/** heading level for the title; match it to the surrounding context */
titleAs?: HTMLTag
description?: string
list?: string[]
action?: string
@@ -19,7 +22,7 @@ interface Props {
[key: string]: unknown
}
const { color = 'success', variant, showClose, class: className, title, description, list, action, link, ...rest } = Astro.props
const { color = 'success', variant, showClose, class: className, title, titleAs: Title = 'h3', description, list, action, link, ...rest } = Astro.props
const defaultIcons: Record<AlertColor, string> = {
success: 'check',
@@ -38,7 +41,7 @@ const classes = ['alert', variant && `alert-${variant}`, `alert-${color}`, showC
description || list ? (
<div>
{/* set:html preserves entities like &hellip; in the title */}
{title && <h4 class="alert-heading" set:html={title} />}
{title && <Title class="alert-heading" set:html={title} />}
<div class="alert-description">
<Fragment set:html={description ?? ''} />
{list && list.length > 0 && (
+3 -1
View File
@@ -51,5 +51,7 @@ const classes = ['avatar', size && `avatar-${size}`, className, shape && `avatar
---
<El {...linkAttrs} class:list={classes} style={src ? `background-image: url(${base}/${src})` : undefined} {...rest}
>{status && <span class={`badge bg-${status}`} aria-label={statusLabel ?? status} />}{brand && <span class="avatar-brand" style={`background-image: url(${base}/static/brands/${brand}.svg);`} />}{src ? null : placeholder ? placeholder : icon ? <Icon name={icon} /> : <Icon name="user" />}</El
>{status && <span class={`badge bg-${status}`} role={statusLabel ? 'img' : undefined} aria-label={statusLabel} />}{brand && <span class="avatar-brand" style={`background-image: url(${base}/static/brands/${brand}.svg);`} />}{
src ? null : placeholder ? placeholder : icon ? <Icon name={icon} /> : <Icon name="user" />
}</El
>
+3 -1
View File
@@ -47,7 +47,7 @@ const Element = element ?? (href && !isAction ? 'a' : 'button')
const resolvedHref = Element === 'a' ? href : undefined
const resolvedType = Element === 'button' ? (type ?? 'button') : undefined
const classes = ['btn', color ? `btn-${variant ? `${variant}-` : ''}${color}` : variant && `btn-${variant}`, size && size !== 'md' && `btn-${size}`, className, block && 'w-100', iconOnly && 'btn-icon', loading && 'btn-loading']
const classes = ['btn', color ? `btn-${variant ? `${variant}-` : ''}${color}` : variant && `btn-${variant}`, size && size !== 'md' && `btn-${size}`, className, block && 'w-100', iconOnly && 'btn-icon', loading && 'btn-loading', Element === 'a' && disabled && 'disabled']
---
<Element
@@ -62,6 +62,8 @@ const classes = ['btn', color ? `btn-${variant ? `${variant}-` : ''}${color}` :
aria-label={iconOnly ? text : undefined}
data-bs-dismiss={dismiss ? 'modal' : undefined}
disabled={Element === 'button' && disabled ? true : undefined}
aria-disabled={Element === 'a' && disabled ? 'true' : undefined}
tabindex={Element === 'a' && disabled ? -1 : undefined}
{...rest}
>
{icon && <Icon name={icon} color={iconColor} />}
+16 -7
View File
@@ -1,4 +1,5 @@
---
import type { HTMLTag } from 'astro/types'
import CaptureScript from '../components/CaptureScript.astro'
interface Props {
id: string
@@ -6,9 +7,11 @@ interface Props {
custom?: boolean
text?: string
description?: string
/** heading level for the custom message title; match it to the surrounding context */
titleAs?: HTMLTag
}
const { id, multiple, custom, text, description } = Astro.props
const { id, multiple, custom, text, description, titleAs: Title = 'h3' } = Astro.props
const label = 'Upload file'
const dropzoneId = `dropzone-${id}`
@@ -16,7 +19,7 @@ const dropzoneSelector = `#dropzone-${id}`
const fileInputId = `${dropzoneId}-file`
---
<form class="dropzone" id={dropzoneId} action="./" autocomplete="off" novalidate tabindex="0" role="button" aria-label="Click or drag files to upload">
<form class="dropzone" id={dropzoneId} action="./" autocomplete="off" novalidate>
<div class="fallback">
<label class="visually-hidden" for={fileInputId}>{label}</label>
<input id={fileInputId} name="file" type="file" multiple={multiple ? '' : undefined} />
@@ -24,7 +27,7 @@ const fileInputId = `${dropzoneId}-file`
{
custom && (
<div class="dz-message">
<h3>{text}</h3>
<Title>{text}</Title>
<span>{description}</span>
</div>
)
@@ -40,12 +43,18 @@ const fileInputId = `${dropzoneId}-file`
const instance = new Dropzone(dropzoneSelector)
window.tabler_dropzone[dropzoneId] = instance
// Dropzone.js is click/drag-only by default: it binds a click handler on the whole
// element but never wires a keyboard equivalent. Since the element is now focusable
// (role="button" + tabindex="0"), forward Enter/Space to a programmatic click on
// Dropzone's own hidden file input so keyboard users can open the file picker too.
// Dropzone.js hides the .fallback label/input once it initializes, which is why
// role="button" + tabindex only get added here rather than in the static markup —
// adding them upfront would nest one focusable control (the fallback input) inside
// another (this "button"). Dropzone.js is also click/drag-only by default: it binds
// a click handler on the whole element but never wires a keyboard equivalent, so
// forward Enter/Space to a programmatic click on Dropzone's own hidden file input.
// Note: that input is appended to <body> (hiddenInputContainer default), not inside
// dropzoneEl, so it must be reached via the instance rather than a DOM query here.
dropzoneEl?.setAttribute('role', 'button')
dropzoneEl?.setAttribute('tabindex', '0')
dropzoneEl?.setAttribute('aria-label', 'Click or drag files to upload')
dropzoneEl?.addEventListener('keydown', (event) => {
if (event.target !== dropzoneEl) return
if (event.key !== 'Enter' && event.key !== ' ' && event.key !== 'Spacebar') return
+1 -1
View File
@@ -18,6 +18,6 @@ interface Props extends PolymorphicProps {
const { as: Element = 'div', action, active, disabled, class: className, ...rest }: Props = Astro.props
---
<Element class:list={['list-group-item', action && 'list-group-item-action', active && 'active', disabled && 'disabled', className]} {...rest}>
<Element class:list={['list-group-item', action && 'list-group-item-action', active && 'active', disabled && 'disabled', className]} aria-disabled={disabled ? 'true' : undefined} tabindex={Element === 'a' && disabled ? -1 : undefined} {...rest}>
<slot />
</Element>
+1 -1
View File
@@ -35,7 +35,7 @@ const classes = ['progress', size && `progress-${size}`, className]
indeterminate ? (
<div class={`progress-bar progress-bar-indeterminate${color ? ` bg-${color}` : ''}`} />
) : valueList ? (
valueList.map((v, i) => <div class={`progress-bar${colors[i] ? ` bg-${colors[i]}` : ''}`} style={`width: ${v}%`} role="progressbar" aria-valuenow={v} aria-valuemin="0" aria-valuemax="100" />)
valueList.map((v, i) => <div class={`progress-bar${colors[i] ? ` bg-${colors[i]}` : ''}`} style={`width: ${v}%`} role="progressbar" aria-valuenow={v} aria-valuemin="0" aria-valuemax="100" aria-label={`${v}%`} />)
) : (
<div class={`progress-bar${color ? ` bg-${color}` : ''}${striped ? ` progress-bar-striped${animated ? ' progress-bar-animated' : ''}` : ''}`} style={`width: ${percentage}%`} role="progressbar" aria-valuenow={percentage} aria-valuemin="0" aria-valuemax="100" aria-label={`${percentage}% Complete`}>
{showValue ? `${percentage}%` : <span class="visually-hidden">{percentage}% Complete</span>}
+1
View File
@@ -65,5 +65,6 @@ const classes = ['sparkline', size && `sparkline-${size}`, (square || isCircle)
data-bs-animation={animation}
data-bs-width={isCircle ? 40 : undefined}
data-bs-height={isCircle ? 40 : undefined}
role={ariaLabel ? 'img' : undefined}
aria-label={ariaLabel}
{...rest}></span>
+6 -4
View File
@@ -6,15 +6,17 @@ interface Props {
class?: string
prepend?: boolean
type?: string
name?: string
value?: string
rounded?: boolean
ariaLabel?: string
readonly?: boolean
placeholder?: string
loader?: boolean
autocomplete?: string
}
const { icon = 'search', class: className, prepend, type = 'text', value = '', rounded, ariaLabel, readonly, placeholder = 'Search…', loader } = Astro.props
const { icon = 'search', class: className, prepend, type = 'text', name, value = '', rounded, ariaLabel, readonly, placeholder = 'Search…', loader, autocomplete } = Astro.props
const wrapperClass = ['input-icon', className]
const addonClass = ['input-icon-addon']
@@ -22,7 +24,7 @@ const controlClass = ['form-control', rounded && 'form-control-rounded']
---
<div class:list={wrapperClass}>
{prepend && <span class:list={addonClass}>{loader ? <div class="spinner-border spinner-border-sm text-secondary" role="status" /> : <Icon name={icon} />}</span>}
<input type={type as astroHTML.JSX.HTMLInputTypeAttribute} value={value} class:list={controlClass} placeholder={placeholder} aria-label={ariaLabel} readonly={readonly} />
{!prepend && <span class:list={addonClass}>{loader ? <div class="spinner-border spinner-border-sm text-secondary" role="status" /> : <Icon name={icon} />}</span>}
{prepend && <span class:list={addonClass}>{loader ? <span class="spinner-border spinner-border-sm text-secondary" role="status" /> : <Icon name={icon} />}</span>}
<input type={type as astroHTML.JSX.HTMLInputTypeAttribute} name={name} value={value} class:list={controlClass} placeholder={placeholder} aria-label={ariaLabel} readonly={readonly} autocomplete={autocomplete} />
{!prepend && <span class:list={addonClass}>{loader ? <span class="spinner-border spinner-border-sm text-secondary" role="status" /> : <Icon name={icon} />}</span>}
</div>