Simple Footer
A logo, one row of links and a copyright line - stacked on mobile, spread on desktop.
6 个框架初级
A locale and currency switcher beside the link row, for a footer that serves several markets.
<!--
A market switcher in the footer: a language <select> and a currency <select>
beside the usual link row. Each select is a real control with its own
visually hidden <label> - a bare select carries no accessible name, so a
screen reader announces only "combobox". The block stacks above md so the
selects never land on top of the links at 320px, and each control is at least
40px tall to stay a usable tap target.
-->
<footer class="border-t border-gray-200 bg-white dark:border-gray-800 dark:bg-gray-900">
<div class="mx-auto flex max-w-6xl flex-col gap-6 px-4 py-8 md:flex-row md:items-center md:justify-between">
<div class="flex flex-col items-center gap-4 sm:flex-row sm:gap-6">
<a href="/" class="font-bold text-gray-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 dark:text-gray-50 dark:focus-visible:ring-blue-400">Adysre</a>
<nav aria-label="Footer">
<ul class="flex flex-wrap justify-center gap-x-5 gap-y-2">
<li><a href="/about" class="text-sm text-gray-700 hover:text-gray-900 hover:underline hover:underline-offset-4 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 dark:text-gray-300 dark:hover:text-gray-50 dark:focus-visible:ring-blue-400">About</a></li>
<li><a href="/pricing" class="text-sm text-gray-700 hover:text-gray-900 hover:underline hover:underline-offset-4 dark:text-gray-300 dark:hover:text-gray-50">Pricing</a></li>
<li><a href="/privacy" class="text-sm text-gray-700 hover:text-gray-900 hover:underline hover:underline-offset-4 dark:text-gray-300 dark:hover:text-gray-50">Privacy</a></li>
</ul>
</nav>
</div>
<div class="flex flex-col gap-3 sm:flex-row sm:items-center">
<div class="flex min-h-10 items-center gap-2 rounded-lg border border-gray-300 px-3 py-2 focus-within:ring-2 focus-within:ring-blue-600 dark:border-gray-700 dark:focus-within:ring-blue-400">
<svg class="h-4 w-4 shrink-0 text-gray-500 dark:text-gray-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
<circle cx="12" cy="12" r="10" />
<path d="M2 12h20M12 2a15 15 0 0 1 0 20 15 15 0 0 1 0-20z" />
</svg>
<label for="footer-lang" class="sr-only">Language</label>
<select id="footer-lang" class="min-w-0 bg-transparent text-sm text-gray-700 focus:outline-none dark:text-gray-300">
<option value="en-US">English (US)</option>
<option value="fr-FR">Français</option>
<option value="de-DE">Deutsch</option>
<option value="ja-JP">日本語</option>
</select>
</div>
<div class="flex min-h-10 items-center gap-2 rounded-lg border border-gray-300 px-3 py-2 focus-within:ring-2 focus-within:ring-blue-600 dark:border-gray-700 dark:focus-within:ring-blue-400">
<label for="footer-cur" class="sr-only">Currency</label>
<select id="footer-cur" class="min-w-0 bg-transparent text-sm text-gray-700 focus:outline-none dark:text-gray-300">
<option value="USD">USD $</option>
<option value="EUR">EUR €</option>
<option value="GBP">GBP £</option>
<option value="JPY">JPY ¥</option>
</select>
</div>
</div>
</div>
<div class="border-t border-gray-200 dark:border-gray-800">
<p class="mx-auto max-w-6xl p-4 text-[0.8125rem] text-gray-500 dark:text-gray-400">
© <time datetime="2026">2026</time> Adysre Inc.
</p>
</div>
</footer>| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
locale | string | 'en-US' | 显示在标题下方的正文文本。 |
currency | string | 'USD' | 显示在标题下方的正文文本。 |
onLocaleChange | (value: string) => void | - | 显示在标题下方的正文文本。 |
onCurrencyChange | (value: string) => void | - | 显示在标题下方的正文文本。 |
className | string | - | 合并到根元素上的额外类名。 |
Each `<select>` is a real control with its own visually hidden `<label>` - a bare select carries no accessible name, so a screen reader announces only "combobox". The focus ring lives on the wrapper via `focus-within`, so the native select keeps its own affordance while the whole control lights up on keyboard focus, and each is at least 40px tall. The selects are uncontrolled (`defaultValue`) with optional `onLocaleChange`/`onCurrencyChange` callbacks, so the component works as static markup or wired to your i18n store. The block stacks above `md` so the switchers never land on top of the links at 320px.