Final recommended stack
Astro 7
+ TypeScript
+ pnpm
+ Node.js 24 LTS
+ Tailwind CSS v4
+ daisyUI v5
+ Alpine.js
+ Pagefind
+ Astro Content Collections
+ Markdown / MDX / JSON / YAML
+ Zod validation
+ @astrojs/sitemap
+ @astrojs/mdx
+ Astro Image / Picture
+ Cheerio + Turndown + gray-matter for migration
+ Playwright + axe-core + Lighthouse CI + HTMLHint for QA
Code language: JavaScript (javascript)
That is the stack I would choose over the Bootstrap variants unless your existing HTML is already heavily Bootstrap-based.
Your best stack should be:
| Layer | Final choice |
|---|---|
| Static site generator | Astro |
| Output | Static HTML/CSS/JS |
| Runtime JavaScript | Minimal islands + Alpine.js only where needed |
| CSS foundation | Tailwind CSS v4 |
| Component class system | daisyUI v5 |
| Interactive UI | Alpine.js |
| Search | Pagefind |
| Content | Astro Content Collections |
| Content formats | Markdown, MDX, JSON, YAML |
| Validation | Zod schemas |
| Pagination | Astro static pagination |
| SEO | Shared SEO component + frontmatter + JSON-LD |
| Breadcrumbs | Generated from taxonomy/category hierarchy |
| Ads | Reusable Astro AdSlot component |
| Migration tooling | Cheerio, Turndown, gray-matter, custom scripts |
| QA | Astro check, HTMLHint, Playwright, axe-core, Lighthouse CI |
Astro is a strong fit because it is built for content-driven sites, produces fast static HTML, and only ships JavaScript where you explicitly need interactivity. Its island architecture lets most of the page stay static HTML while only small components become interactive. (Astro Documentation) Astro can prerender pages as static output, builds to a deploy-ready dist/ folder, and supports static pagination for generated routes. (Astro Documentation)
As of July 9, 2026, Astro 7 is current, and Astro 7 introduced Vite 8, the Rust compiler, advanced routing, a background dev server, and structured logging. (npm) If you are risk-averse, start the migration pilot on Astro 6.4 and upgrade after the first successful batch. For a new build, I would start with Astro 7 after a small smoke test.
My strongest recommendation
Use:
Astro + Tailwind CSS + daisyUI + Alpine.js + Pagefind
Code language: CSS (css)
Do not use:
Astro + Bootstrap + Tailwind + Flowbite + daisyUI
That becomes too heavy and inconsistent.
Also avoid using both Flowbite and daisyUI as primary component systems. Pick one.
My choice for your use case is:
Tailwind CSS + daisyUI + Alpine.js
Code language: CSS (css)
Why? Because your site sounds content-heavy, listing-heavy, category-heavy, SEO-heavy, and theme-heavy. daisyUI gives you semantic component classes and theme support on top of Tailwind, while Alpine.js gives you lightweight behavior for dropdowns, mobile menus, accordions, filter panels, tabs, modals, and small stateful UI. daisyUI v5 is a Tailwind component library with built-in themes and custom theme support. (daisyUI) Alpine.js is designed for adding minimal interactivity directly in HTML-like markup. (Alpine.js)
Flowbite is also good, especially if you want many ready-made Tailwind components with JavaScript/data-attribute behavior. It has Astro integration and interactive UI components. (Flowbite) But for a long-lived custom MyMedicPlus design system, I would rather use daisyUI for component styling and Alpine.js for behavior.
When Bootstrap is still the better choice
There is one case where I would choose Bootstrap:
Astro + Bootstrap 5.3 + custom SCSS + Pagefind
Code language: CSS (css)
Choose this only if 60โ70% of your existing HTML pages already use Bootstrap classes or your team is much faster with Bootstrap than Tailwind.
Bootstrap 5.3 has mature Sass customization through variables, maps, mixins, functions, color options, and theming. (Bootstrap) So for a low-risk legacy migration, Bootstrap can be practical.
But if you are building the future stack, I would choose Tailwind/daisyUI.
Final decision table
| Requirement | Recommended technology | Reason |
|---|---|---|
| HTML-only final site | Astro static output | Clean static HTML/CSS/JS |
| Thousands of pages | Astro Content Collections | Typed content, build-time routes |
| Easy future pages | Markdown / MDX | Editors can create content without touching templates |
| Structured data pages | JSON / YAML | Good for categories, taxonomy, nav, ads, redirects |
| Common header/menu/footer | Astro layouts/components | One source of truth |
| Mobile-first layout | Tailwind CSS | Strong responsive utility system |
| Custom MyMedicPlus theme | Tailwind theme + daisyUI themes + CSS variables | Brand tokens stay centralized |
| UI components | daisyUI | Buttons, cards, badges, alerts, dropdown styling |
| Mobile menu/dropdowns | Alpine.js | Lightweight, no full frontend framework |
| FAQ accordions | Alpine.js or daisyUI collapse | Simple static-friendly interaction |
| Search | Pagefind | Fully static search index |
| Search filters | Pagefind filters + generated category URLs | Static-first and SEO-friendly |
| Sort | Static default sort + Pagefind sort for search results | Avoids fake sorting of only visible page |
| Pagination | Astro paginate() | Build-time static pagination |
| Breadcrumbs | Astro component + taxonomy data + JSON-LD | SEO and UX |
| SEO | Shared SEO.astro component + frontmatter | Consistent metadata |
| Schema markup | Reusable JSON-LD component | Breadcrumb, Article, FAQ, CollectionPage |
| Ads | AdSlot.astro + frontmatter/config | Easy enable/disable |
| Legacy HTML migration | Cheerio + Turndown + gray-matter | Parse, clean, convert, add frontmatter |
| Validation | Zod | Catch bad/missing fields before build |
| Accessibility testing | Playwright + axe-core | Catch common a11y issues |
| Performance/SEO CI | Lighthouse CI | Prevent regressions |
| HTML quality | HTMLHint | Static HTML checks |
How the listing-page article maps to a static site
The article you referenced lists features like search, filters, sorting, pagination, result count, row actions, bulk actions, export, loading state, empty state, error state, mobile responsiveness, URL persistence, and server-side handling. (Rajesh Kumar)
For a public static site, you should reinterpret some of those features.
Public static listing page standard
For MyMedicPlus or a similar large content site, I would define every major listing/category page like this:
| Feature | Static-site implementation |
|---|---|
| Breadcrumb | Breadcrumbs.astro from taxonomy tree |
| H1 title | Page frontmatter or category data |
| SEO intro paragraph | Markdown/MDX/category description |
| Search box | Pagefind search |
| Filter panel | Static category/tag/location pages + Pagefind metadata filters |
| Sort dropdown | Build-time sort for listings; Pagefind sort for search results |
| Result count | Build-time count from content collection |
| Listing cards | ListingCard.astro |
| Pagination | Astro paginate() |
| Items per page | Fixed SEO-safe page size, usually 12, 18, or 24 |
| Optional ad block | AdSlot.astro controlled by frontmatter/config |
| Empty state | EmptyState.astro |
| Related categories | Generated from taxonomy/category map |
| FAQ section | Visible content section, optional FAQ schema |
| Schema markup | JSON-LD component |
| Mobile-first layout | Tailwind responsive cards |
| URL query persistence | Search/filter UI uses URLSearchParams |
| Search indexing | Pagefind after Astro build |
| Sitemap inclusion | @astrojs/sitemap |
This is the correct static version of the articleโs listing-page standard.
Important correction: not every app feature belongs in static HTML
The article includes admin-style features such as:
row actions
bulk actions
delete
permission-based actions
server-side search/filter/sort/pagination
create button
export
refresh
confirmation modal
Code language: JavaScript (javascript)
Those are correct for admin applications, but not always for public static websites.
For your static site, the equivalent is:
| App listing feature | Static-site equivalent |
|---|---|
| Server-side pagination | Build-time pagination |
| Server-side search | Static Pagefind index |
| Server-side filters | Generated category/tag/location pages |
| URL query persistence | Client-side query params for search UI |
| Permissions | Not applicable in public static HTML |
| Bulk actions | Not applicable unless separate admin tool |
| Row delete/edit | Not applicable unless separate CMS/admin app |
| Export | Optional static download or generated CSV/JSON |
| Refresh | Rebuild/redeploy pipeline |
The big warning: do not implement โsecure permissionsโ in client-side static HTML. If you need create/edit/delete/approval workflows, build that as a separate authenticated admin/CMS system and publish the output as static HTML.
Recommended architecture
Use Astro as the publishing engine.
Content files + data files
โ
Astro content collections
โ
Typed schemas and validation
โ
Layouts and reusable components
โ
Static category/listing/detail pages
โ
Pagefind static search index
โ
dist/ static website
โ
CDN / static hosting
Code language: PHP (php)
Astro Content Collections are a strong fit here because they support Markdown, MDX, JSON, YAML, TOML, schemas, and build-time page generation. Astroโs docs also describe content collections as useful for thousands or tens of thousands of pages when content is loaded and queried at build time. (Astro Documentation)
Suggested project structure
mymedicplus-site/
astro.config.mjs
package.json
tsconfig.json
src/
content.config.ts
content/
pages/
articles/
conditions/
treatments/
hospitals/
doctors/
categories/
data/
nav.yaml
taxonomy.yaml
redirects.csv
ads.yaml
authors.yaml
reviewers.yaml
layouts/
BaseLayout.astro
ContentLayout.astro
ListingLayout.astro
CategoryLayout.astro
components/
seo/
SEO.astro
JsonLd.astro
nav/
Header.astro
Footer.astro
Breadcrumbs.astro
MobileMenu.astro
listing/
ListingShell.astro
SearchBox.astro
FilterPanel.astro
SortSelect.astro
ResultCount.astro
ListingCard.astro
Pagination.astro
EmptyState.astro
RelatedCategories.astro
FAQ.astro
ads/
AdSlot.astro
ui/
Button.astro
Card.astro
Badge.astro
Alert.astro
Modal.astro
Accordion.astro
pages/
index.astro
search.astro
categories/[...slug].astro
articles/[...slug].astro
conditions/[...slug].astro
treatments/[...slug].astro
hospitals/[...slug].astro
doctors/[...slug].astro
scripts/
migrate/
inventory-html.ts
extract-html.ts
convert-to-mdx.ts
classify-pages.ts
validate-content.ts
generate-redirects.ts
public/
assets/
images/
Code language: PHP (php)
Content format recommendation
Use different formats for different kinds of content.
| Content type | Best format |
|---|---|
| Long articles | Markdown or MDX |
| Medical condition pages | MDX |
| Treatment pages | MDX |
| Category landing pages | Markdown/MDX with frontmatter |
| Hospital/doctor directories | JSON/YAML if highly structured; MDX if each has rich body content |
| Navigation | YAML |
| Taxonomy | YAML or JSON |
| Ads configuration | YAML |
| Redirect map | CSV or YAML |
| FAQ data | Frontmatter or embedded MDX component |
| Legacy pages during migration | MDX or cleaned HTML inside Astro layout |
For thousands of unstructured pages, do not try to manually rewrite everything immediately. First convert them into a normalized โlegacy contentโ format, then progressively improve the most important pages.
Example content schema
You should force every page to have required metadata. This is what stops the new site from becoming another unstructured mess.
// src/content.config.ts
import { defineCollection } from "astro:content";
import { glob, file } from "astro/loaders";
import { z } from "astro/zod";
const pages = defineCollection({
loader: glob({
base: "./src/content/pages",
pattern: "**/*.{md,mdx}",
}),
schema: z.object({
title: z.string(),
description: z.string().max(170),
slug: z.string().optional(),
legacyUrl: z.string().optional(),
category: z.string().optional(),
tags: z.array(z.string()).default([]),
updatedAt: z.coerce.date(),
reviewedBy: z.string().optional(),
author: z.string().optional(),
noindex: z.boolean().default(false),
ads: z.boolean().default(true),
faqs: z
.array(
z.object({
q: z.string(),
a: z.string(),
})
)
.default([]),
}),
});
const taxonomy = defineCollection({
loader: file("./src/data/taxonomy.yaml"),
schema: z.object({
id: z.string(),
title: z.string(),
slug: z.string(),
parent: z.string().optional(),
description: z.string().optional(),
}),
});
export const collections = {
pages,
taxonomy,
};
Code language: JavaScript (javascript)
Zod is a TypeScript-first validation library, and gray-matter can parse frontmatter from strings/files during migration. (Zod)
Pagefind search strategy
Use Pagefind for static search.
Pagefind is specifically built for fully static, low-bandwidth search at scale, with no hosting infrastructure required. It runs after your static site generator and creates a static search bundle inside the generated site. (Pagefind)
Your build should work like this:
astro build
pagefind --site dist
Use Pagefind attributes inside templates:
<main data-pagefind-body>
...
</main>
<span data-pagefind-filter="category">Hospitals</span>
<span data-pagefind-filter="location">India</span>
<span data-pagefind-sort="updated">2026-07-01</span>
Code language: HTML, XML (xml)
Pagefind supports data-pagefind-body, filters, sort values, and a JavaScript API for filters/sorting. (Pagefind)
Search UX recommendation
Have two types of search/filter pages:
1. SEO category pages
These should be static and crawlable:
/hospitals/
/hospitals/india/
/hospitals/india/delhi/
/treatments/cardiology/
/conditions/diabetes/
Code language: JavaScript (javascript)
These pages should have:
H1
intro text
breadcrumb
listing cards
static pagination
related categories
FAQ
schema
canonical URL
Code language: JavaScript (javascript)
2. Interactive search page
Use Pagefind for user convenience:
/search/?q=heart&category=hospitals&location=delhi
This page can support:
search box
filters
sort
result count
reset filters
empty state
URL query persistence
Code language: PHP (php)
Do not rely only on JavaScript filters for SEO-important category pages. Important filter combinations should become real generated URLs.
Pagination strategy
Use Astro static pagination for category/listing pages. Astroโs paginate() automatically generates URLs for each page in a paginated collection. (Astro Documentation)
Recommended URL pattern:
/hospitals/
/hospitals/2/
/hospitals/3/
Code language: JavaScript (javascript)
Avoid this for SEO-critical pages:
/hospitals?page=2
For items per page, I would not make it fully dynamic on public SEO pages. Use a fixed page size:
12 cards per page for visual directories
24 items per page for compact lists
50 items per page for simple text directories
A dynamic ?per_page=12|24|48 creates duplicate/canonical complexity. Keep that kind of behavior only on the /search/ page.
Breadcrumb and schema strategy
Generate breadcrumbs from taxonomy, not manually.
Example:
Home > Treatments > Cardiology > Heart Surgery
Use:
Breadcrumbs.astro
JsonLd.astro
taxonomy.yaml
Code language: CSS (css)
Googleโs breadcrumb structured data documentation says breadcrumbs indicate a pageโs position in the site hierarchy and help users understand and explore the site. (Google for Developers) Schema.org also defines BreadcrumbList for breadcrumb structures. (Schema.org)
Use JSON-LD for:
| Page type | Schema |
|---|---|
| Article | Article or BlogPosting |
| Medical content | Use appropriate medical schema carefully, only when accurate |
| FAQ section | FAQPage only when FAQ is visible on page |
| Breadcrumbs | BreadcrumbList |
| Listing/category page | CollectionPage or WebPage |
| Organization | Organization |
| Website search | WebSite with search action, where appropriate |
Important: Google announced that FAQ rich results are no longer shown in Google Search as of May 2026, so do not treat FAQ schema as a guaranteed SEO-rich-result tactic. Keep FAQs because they help users and page quality. (Google for Developers)
SEO stack
Use one shared SEO component.
SEO.astro
JsonLd.astro
Canonical.astro
OpenGraph.astro
Code language: CSS (css)
Every page should have:
title
meta description
canonical URL
robots setting
Open Graph title
Open Graph description
Open Graph image
breadcrumb JSON-LD
page-specific schema
last updated date
author/reviewer where relevant
Code language: JavaScript (javascript)
Google recommends using canonical URLs consistently and supports rel="canonical" as a way to indicate the preferred URL. (Google for Developers) The @astrojs/sitemap integration can generate sitemap indexes and sitemap files from your site URL. (Astro Documentation)
Because MyMedicPlus sounds health-related, treat the site as YMYL content. Googleโs guidance around helpful, reliable, people-first content and quality-rater guidance applies especially strongly to topics where low-quality information could affect health, safety, or finances. (Google for Developers)
For medical pages, add:
author
medical reviewer
reviewed date
updated date
sources/references
disclaimer
clear ownership/about information
contact information
editorial policy
That matters more than stuffing pages with schema.
CSS and design-system recommendation
Use Tailwind v4 with:
@tailwindcss/typography
@tailwindcss/forms
daisyUI
custom CSS variables
Code language: CSS (css)
Tailwindโs official Astro installation now uses the Vite plugin, and the older @astrojs/tailwind integration is deprecated for newer Tailwind usage. (Tailwind CSS)
Use the Typography plugin for migrated article content, because it gives good default styling for raw Markdown or HTML-like content you do not fully control. (GitHub) Use the Forms plugin for consistent form controls. (GitHub)
Very important Tailwind migration warning
Tailwind scans source files as plain text and does not understand dynamically generated class names. It will not reliably detect code like:
`bg-${color}-500`
Code language: JavaScript (javascript)
Tailwind recommends mapping dynamic values to complete class names instead. (Tailwind CSS)
So for migrated pages, avoid letting content generate arbitrary Tailwind classes. Use:
content body โ prose classes
components โ controlled Tailwind classes
theme values โ CSS variables
This keeps the design consistent and avoids broken production CSS.
Component library decision
Best choice
Tailwind + daisyUI + Alpine.js
Code language: CSS (css)
Use daisyUI for:
buttons
cards
badges
alerts
dropdown styling
tabs
accordions/collapse styling
modal styling
pagination styling
form styling
theme tokens
Use Alpine.js for:
mobile menu
dropdown open/close
filter panel
accordion behavior
FAQ expand/collapse
modal state
tabs
reset filters
URL query persistence
Alpine supports small reactive blocks using x-data, and its collapse plugin supports smooth show/hide behavior with x-show and x-collapse. (Alpine.js)
Alternative
Tailwind + Flowbite + minimal Alpine
Use this if you want more prebuilt copy-paste components and are okay using Flowbiteโs JavaScript behavior.
Avoid
Tailwind + Flowbite + daisyUI + Bootstrap
That is too much. You will end up debugging CSS specificity, duplicate components, inconsistent spacing, and design drift.
Listing-page component standard
Create one reusable listing system.
ListingLayout.astro
ListingShell.astro
SearchBox.astro
FilterPanel.astro
SortSelect.astro
ResultCount.astro
ListingCard.astro
Pagination.astro
EmptyState.astro
RelatedCategories.astro
FAQ.astro
AdSlot.astro
Code language: CSS (css)
Standard category listing page
Each category landing page should include:
1. Breadcrumb
2. H1 page title
3. SEO intro paragraph
4. Optional hero/summary card
5. Search box or link to search page
6. Category/type filters
7. Sort dropdown, if useful
8. Total result count
9. Paginated cards/listings
10. Fixed items per page
11. Reset filters button where filters exist
12. Empty state
13. Optional ad block
14. Related categories
15. FAQ section
16. Schema markup
17. Canonical URL
18. Sitemap inclusion
19. Mobile-first layout
Code language: PHP (php)
Recommended behavior
| Feature | Recommendation |
|---|---|
| Search box | On /search/; optional compact search on category pages |
| Filters | Static URLs for SEO-important filters; Pagefind filters for interactive search |
| Sort | Default static sort by relevance/name/date; optional Pagefind sorting |
| Result count | Build-time count |
| Pagination | Static Astro pagination |
| Reset filters | Alpine/vanilla JS |
| URL persistence | Use query params only for search UI |
| Empty state | Custom text based on category/filter |
| Ads | Controlled by frontmatter |
| FAQ | Visible content, not hidden SEO bait |
| Schema | Generated, never manually copied page by page |
Example listing page data model
For category pages:
id: hospitals-india
title: Hospitals in India
slug: /hospitals/india/
parent: hospitals
description: Find hospitals in India by specialty, location, and treatment category.
seoTitle: Hospitals in India | MyMedicPlus
seoDescription: Browse hospitals in India by specialty, city, and treatment category.
filters:
- specialty
- city
- treatment
ads: true
faqs:
- q: How do I choose a hospital in India?
a: Compare specialty, accreditation, doctor availability, and patient support services.
Code language: JavaScript (javascript)
For content pages:
title: Heart Surgery in India
description: Learn about heart surgery options, hospital selection, recovery, and planning.
category: cardiology
tags:
- heart surgery
- cardiology
- india
updatedAt: 2026-07-01
reviewedBy: Dr Example
ads: true
legacyUrl: /old/heart-surgery-india.html
Code language: JavaScript (javascript)
Migration strategy for thousands of unstructured HTML pages
Do not manually migrate everything.
Use a staged migration.
Phase 1: Inventory
Write a script that scans all old HTML files and extracts:
old file path
old URL
title tag
meta description
canonical
H1
H2s
main content selector
internal links
images
scripts
inline styles
tables
forms
detected page type
word count
broken/missing metadata
Use Cheerio for parsing. Cheerio is widely used for parsing and manipulating HTML/XML in JavaScript and provides a jQuery-like API. (Cheerio)
Output:
migration-inventory.csv
redirect-map.csv
content-quality-report.csv
Code language: CSS (css)
Phase 2: Classify pages
Group old pages into page types:
article
condition page
treatment page
hospital page
doctor page
category landing page
FAQ page
listing page
legacy/misc page
thin/duplicate page
redirect-only page
This matters because a hospital page, a treatment article, and a category page should not share the same schema or layout.
Phase 3: Extract main content
Strip old:
header
footer
nav
old sidebars
old ad blocks
tracking scripts
inline JavaScript
duplicate breadcrumbs
outdated menus
layout tables
Keep:
main article body
headings
paragraphs
lists
tables
images
important links
FAQs
citations/sources
Phase 4: Convert to Markdown/MDX
Use Turndown for HTML-to-Markdown conversion. Turndown is a JavaScript HTML-to-Markdown converter. (GitHub)
Recommended rule:
| Legacy content | Convert to |
|---|---|
| Normal article body | Markdown |
| Article with custom components | MDX |
| Complex tables | Keep as HTML or convert to Astro component |
| Old forms | Rebuild as component |
| Old scripts/widgets | Replace, do not blindly migrate |
| Layout wrappers | Delete |
| Old ad code | Replace with AdSlot.astro |
Phase 5: Add frontmatter
Use gray-matter to create frontmatter. (GitHub)
Example generated file:
---
title: "Heart Surgery in India"
description: "Learn about heart surgery in India, hospital selection, recovery, and treatment planning."
legacyUrl: "/old/heart-surgery-india.html"
category: "cardiology"
tags:
- heart surgery
- india
updatedAt: "2026-07-01"
ads: true
---
# Heart Surgery in India
Migrated content here...
Code language: PHP (php)
Phase 6: Preserve URLs or create redirects
For pages with traffic/backlinks, preserve the old URL where possible.
If URL must change, create a redirect map:
from,to,status
/old/heart-surgery-india.html,/treatments/cardiology/heart-surgery-india/,301
Code language: JavaScript (javascript)
Astro supports configured redirects, but static redirects ultimately depend on your hosting platform. Astroโs runtime Astro.redirect is server-side and not available for static-only output, so static deployments should use hosting redirects or generated redirect files where supported. (Astro Documentation)
Phase 7: Progressive cleanup
Do not perfect all 1,000+ pages before launch.
Use this order:
1. High-traffic pages
2. High-value SEO pages
3. Category landing pages
4. Medical/YMYL pages needing review
5. Pages with backlinks
6. Thin/duplicate pages
7. Low-value legacy pages
Code language: JavaScript (javascript)
First make the pages render correctly inside Astro. Then improve the important ones.
Build and package setup
Use Node.js 24 LTS and pnpm. Nodeโs official release page lists v24.18.0 as the latest LTS line as of the current release information, and pnpm describes itself as a fast, disk-space-efficient package manager with workspace support. (Node.js)
Suggested install:
pnpm create astro@latest mymedicplus-site
cd mymedicplus-site
pnpm add alpinejs @alpinejs/collapse @alpinejs/focus @alpinejs/persist
pnpm add lucide-astro
pnpm add -D @astrojs/check @astrojs/mdx @astrojs/sitemap typescript
pnpm add -D tailwindcss @tailwindcss/vite daisyui @tailwindcss/typography @tailwindcss/forms
pnpm add -D pagefind
pnpm add -D cheerio turndown gray-matter fast-glob js-yaml
pnpm add -D htmlhint @playwright/test @axe-core/playwright @lhci/cli
Code language: CSS (css)
Suggested scripts:
{
"scripts": {
"dev": "astro dev",
"check": "astro check",
"build": "astro build && pagefind --site dist",
"preview": "astro build && pagefind --site dist --serve",
"lint:html": "htmlhint \"dist/**/*.html\"",
"test:a11y": "playwright test",
"lhci": "lhci autorun"
}
}
Code language: JSON / JSON with Comments (json)
Pagefind is designed to run after your static site generator has produced the site. (Pagefind) Astroโs preview command serves the built dist/ directory by default. (Astro Documentation)
Accessibility requirements
Build this into the design system from day one.
For listing pages:
search input has visible label
filters are keyboard accessible
sort dropdown has label
pagination links are real links
current page is announced
cards have clear heading hierarchy
icon buttons have accessible labels
accordions are keyboard usable
modals return focus correctly
loading and no-results states are announced
Code language: JavaScript (javascript)
WCAG 2.2 defines testable accessibility success criteria for web content. (W3C) For sortable tables, WAI-ARIAโs example recommends native table markup, aria-sort on the sorted column, and button text inside sortable headers. (W3C)
Use:
@axe-core/playwright
Playwright
Lighthouse CI
manual keyboard testing
Code language: CSS (css)
Playwrightโs accessibility testing guidance with axe can catch issues such as color contrast, unlabeled controls, and duplicate IDs. Lighthouse CI can run reports in pull requests and prevent performance, accessibility, and SEO regressions. (Playwright)
Quality gates before publishing
Every build should check:
Astro type/content validation
missing title
missing meta description
duplicate title
duplicate canonical
missing H1
multiple H1s
broken internal links
missing image alt text
oversized images
invalid schema JSON
missing breadcrumb
missing sitemap entry
Pagefind index built
HTMLHint passed
accessibility smoke tests passed
Lighthouse budget passed
Code language: JavaScript (javascript)
HTMLHint is a static analysis tool for HTML. (HTMLHint)
What I would not do
I would not choose this:
HTML5 + Tailwind + Alpine + Flowbite + daisyUI
Too many UI systems.
I would not choose this either:
Astro + Bootstrap + Tailwind
Two CSS frameworks will fight each other.
I would not build thousands of static pages by copying old HTML into new templates manually.
I would not make all filters query-string-only if they matter for SEO.
I would not rely on FAQ schema as an SEO trick.
I would not put admin/edit/delete/security behavior into static public HTML.
Best final stack summary
Your final technology stack should be:
| Area | Final choice |
|---|---|
| Static generator | Astro 7 |
| Package manager | pnpm |
| Runtime/build | Node.js 24 LTS |
| Language | TypeScript |
| Styling | Tailwind CSS v4 |
| Component layer | daisyUI v5 |
| Small interactivity | Alpine.js |
| Search | Pagefind |
| Content | Astro Content Collections |
| Article format | Markdown / MDX |
| Structured data | JSON / YAML |
| Validation | Zod |
| Migration parser | Cheerio |
| HTML to Markdown | Turndown |
| Frontmatter generation | gray-matter |
| Sitemap | @astrojs/sitemap |
| Rich content | @astrojs/mdx |
| Images | Astro Image / Picture |
| Accessibility testing | Playwright + axe-core |
| SEO/performance testing | Lighthouse CI |
| HTML linting | HTMLHint |
The clean conclusion:
Astro + Tailwind + daisyUI + Alpine + Pagefind
is the best long-term stack for your large static website.
Use Bootstrap only if your old site is already deeply Bootstrap-based and speed of migration matters more than building a cleaner future design system.
Iโm a DevOps/SRE/DevSecOps/Cloud Expert passionate about sharing knowledge and experiences. I have worked at Cotocus. I share tech blog at DevOps School, travel stories at Holiday Landmark, stock market tips at Stocks Mantra, health and fitness guidance at My Medic Plus, product reviews at TrueReviewNow , and SEO strategies at Wizbrand.
Do you want to learn Quantum Computing?
Please find my social handles as below;
Rajesh Kumar Personal Website
Rajesh Kumar at YOUTUBE
Rajesh Kumar at INSTAGRAM
Rajesh Kumar at X
Rajesh Kumar at FACEBOOK
Rajesh Kumar at LINKEDIN
Rajesh Kumar at WIZBRAND
Find Trusted Cardiac Hospitals
Compare heart hospitals by city and services โ all in one place.
Explore Hospitals