Enhance accessibility and structure across multiple components

- Updated the ContactForm component to include labels and aria-describedby attributes for better accessibility.
- Improved the Button component by conditionally adding aria-labels based on text input.
- Enhanced the Form component with aria-describedby attributes for validation feedback.
- Refactored the Layout component to include semantic HTML5 elements for better structure and accessibility.
- Updated the 404 page metadata for improved SEO and user experience.
This commit is contained in:
2025-06-24 21:05:49 +02:00
parent 0b16ad5a28
commit 3847f415d6
5 changed files with 41 additions and 13 deletions

View File

@@ -1,6 +1,10 @@
<form id="contact-form"> <form id="contact-form">
<input type="email" name="email" id="email" required /> <label for="email">Email</label>
<textarea name="message" id="message" required></textarea> <input type="email" name="email" id="email" required aria-describedby="email-help" />
<div id="email-help" class="sr-only">Enter your email address</div>
<label for="message">Message</label>
<textarea name="message" id="message" required aria-describedby="message-help"></textarea>
<div id="message-help" class="sr-only">Enter your message</div>
<button type="submit">Send</button> <button type="submit">Send</button>
</form> </form>
@@ -10,8 +14,12 @@
If you believe this is a mistake, you can request a manual review. If you believe this is a mistake, you can request a manual review.
</p> </p>
<form id="manual-review-form"> <form id="manual-review-form">
<input type="email" id="manual-email" readonly /> <label for="manual-email">Email</label>
<textarea id="manual-justification" placeholder="Why is this not spam? (optional)"></textarea> <input type="email" id="manual-email" readonly aria-describedby="manual-email-help" />
<div id="manual-email-help" class="sr-only">Re-enter your email address for confirmation</div>
<label for="manual-justification">Why is this not spam? (optional)</label>
<textarea id="manual-justification" placeholder="Why is this not spam? (optional)" aria-describedby="manual-justification-help"></textarea>
<div id="manual-justification-help" class="sr-only">Explain why your message is legitimate</div>
<input type="hidden" id="manual-token" /> <input type="hidden" id="manual-token" />
<button type="submit">Request Manual Review</button> <button type="submit">Request Manual Review</button>
</form> </form>

View File

@@ -19,11 +19,13 @@ const variants = {
tertiary: 'btn btn-tertiary', tertiary: 'btn btn-tertiary',
link: 'cursor-pointer hover:text-primary', link: 'cursor-pointer hover:text-primary',
}; };
const ariaLabel = !text || (typeof text === 'string' && text.trim() === '') ? Astro.props['aria-label'] : undefined;
--- ---
{ {
type === 'button' || type === 'submit' || type === 'reset' ? ( type === 'button' || type === 'submit' || type === 'reset' ? (
<button type={type} class={twMerge(variants[variant] || '', className)} {...rest}> <button type={type} class={twMerge(variants[variant] || '', className)} {...rest} {...(ariaLabel ? { 'aria-label': ariaLabel } : {})}>
<Fragment set:html={text} /> <Fragment set:html={text} />
{icon && <Icon name={icon} class="w-5 h-5 ml-1 -mr-1.5 rtl:mr-1 rtl:-ml-1.5 inline-block" />} {icon && <Icon name={icon} class="w-5 h-5 ml-1 -mr-1.5 rtl:mr-1 rtl:-ml-1.5 inline-block" />}
</button> </button>
@@ -32,6 +34,7 @@ const variants = {
class={twMerge(variants[variant] || '', className)} class={twMerge(variants[variant] || '', className)}
{...(target ? { target: target, rel: 'noopener noreferrer' } : {})} {...(target ? { target: target, rel: 'noopener noreferrer' } : {})}
{...rest} {...rest}
{...(ariaLabel ? { 'aria-label': ariaLabel } : {})}
> >
<Fragment set:html={text} /> <Fragment set:html={text} />
{icon && <Icon name={icon} class="w-5 h-5 ml-1 -mr-1.5 rtl:mr-1 rtl:-ml-1.5 inline-block" />} {icon && <Icon name={icon} class="w-5 h-5 ml-1 -mr-1.5 rtl:mr-1 rtl:-ml-1.5 inline-block" />}

View File

@@ -59,8 +59,9 @@ const { inputs, textarea, disclaimer, button = 'Contact us', description = '' }
placeholder={placeholder} placeholder={placeholder}
class="py-3 px-4 block w-full text-md rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-slate-900" class="py-3 px-4 block w-full text-md rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-slate-900"
required={required} required={required}
aria-describedby={`invalid-feedback-${name}`}
/> />
<div class="invalid-feedback hidden text-red-600 text-sm mt-1" /> <div id={`invalid-feedback-${name}`} class="invalid-feedback hidden text-red-600 text-sm mt-1" />
</div> </div>
) )
) )
@@ -80,8 +81,9 @@ const { inputs, textarea, disclaimer, button = 'Contact us', description = '' }
placeholder={textarea.placeholder} placeholder={textarea.placeholder}
class="py-3 px-4 block w-full text-md rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-slate-900" class="py-3 px-4 block w-full text-md rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-slate-900"
required required
aria-describedby="invalid-feedback-textarea"
/> />
<div class="invalid-feedback hidden text-red-600 text-sm mt-1" /> <div id="invalid-feedback-textarea" class="invalid-feedback hidden text-red-600 text-sm mt-1" />
</div> </div>
) )
} }
@@ -96,6 +98,7 @@ const { inputs, textarea, disclaimer, button = 'Contact us', description = '' }
type="checkbox" type="checkbox"
class="cursor-pointer mt-1 py-3 px-4 block w-full text-md rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-slate-900" class="cursor-pointer mt-1 py-3 px-4 block w-full text-md rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-slate-900"
required required
aria-describedby="invalid-feedback-disclaimer"
/> />
</div> </div>
<div class="ml-3"> <div class="ml-3">
@@ -103,7 +106,7 @@ const { inputs, textarea, disclaimer, button = 'Contact us', description = '' }
{disclaimer.label} {disclaimer.label}
<span class="text-red-600">*</span> <span class="text-red-600">*</span>
</label> </label>
<div class="invalid-feedback hidden text-red-600 text-sm mt-1" /> <div id="invalid-feedback-disclaimer" class="invalid-feedback hidden text-red-600 text-sm mt-1" />
</div> </div>
</div> </div>
) )

View File

@@ -67,9 +67,19 @@ const { language, textDirection } = I18N;
<body class="antialiased text-default bg-page tracking-tight"> <body class="antialiased text-default bg-page tracking-tight">
<GlobalBackground /> <GlobalBackground />
<slot name="structured-data" /> <header role="banner">
<slot /> <slot name="header" />
</header>
<nav role="navigation" aria-label="Main navigation">
<slot name="navigation" />
</nav>
<main role="main">
<slot name="structured-data" />
<slot />
</main>
<footer role="contentinfo">
<slot name="footer" />
</footer>
<BasicScripts /> <BasicScripts />
<LanguagePersistence /> <LanguagePersistence />
<CookieBanner /> <CookieBanner />

View File

@@ -2,7 +2,11 @@
import Layout from '~/layouts/Layout.astro'; import Layout from '~/layouts/Layout.astro';
import { getHomePermalink } from '~/utils/permalinks'; import { getHomePermalink } from '~/utils/permalinks';
const title = `Error 404`; const metadata = {
title: '404 Not Found | 365DevNet',
description: 'Sorry, the page you are looking for does not exist. Return to the homepage or explore other sections of 365DevNet.',
robots: { index: false, follow: false },
};
--- ---
<style> <style>
@@ -382,7 +386,7 @@ const title = `Error 404`;
} }
</style> </style>
<Layout metadata={{ title }}> <Layout metadata={metadata}>
<section class="clean-404-bg"> <section class="clean-404-bg">
<div class="floating-elements-404"> <div class="floating-elements-404">
<div class="floating-shape-404 shape-404-1"></div> <div class="floating-shape-404 shape-404-1"></div>