Nasaq

SeoPageList

A pages list with SEO score, open-issue count, index status and Core Web Vitals, plus a per-page issue checklist with fix hints.

PreviewOpen ↗

Code

import { SeoPageList, type SeoPageRow } from "@fadymondy/nasaq/web";export function Audit({ pages }: { pages: SeoPageRow[] }) {  return <SeoPageList pages={pages} onOpen={(p) => console.log(p.url)} onRecrawl={async (p) => {}} />;}

SEO · beta

Live examples and controls: SeoPageList in the lab.

Install

npx shadcn@latest add https://docs.nasaqui.com/r/seo-pages.json

SeoPageList lists crawled pages with a 0 to 100 SEO score, the number of open issues, index status and the three Core Web Vitals. Opening a page shows SeoIssueChecklist: each issue has a severity, a plain explanation and a fix hint, and can be ticked off as fixed, which raises the score at once. The list is a DataTable, so sorting, search, paging and row actions come with it.

When to use

  • A site audit screen after a crawl.
  • A marketing dashboard that needs to show which pages need work first.

When not to use

Import

import { SeoIssueChecklist, SeoPageList } from "@fadymondy/nasaq/web";

Quick start

import { SeoPageList, type SeoPageRow } from "@fadymondy/nasaq/web";

export function Audit({ pages }: { pages: SeoPageRow[] }) {
  return <SeoPageList pages={pages} onOpen={(p) => console.log(p.url)} onRecrawl={async (p) => {}} />;
}

Anatomy

SeoPageList          data-slot="seo-page-list"   (Card + DataTable)
  toolbar            search, index status facet
  row                URL, score meter, issues, index status, LCP, INP, CLS, crawled
SeoIssueChecklist    data-slot="seo-issue-checklist"
  issue              checkbox, severity, title, fix hint (collapsible)

API

SeoPageList

PropTypeDefaultDescription
pagesSeoPageRow[]requiredRows.
onOpen(page) => voidnoneRow click and the Open action.
onRecrawl(page) => Promise<void | { error?: string }>noneAdds a Recrawl action.
onRequestIndexing(page) => Promise<void | { error?: string }>noneAdds a Request indexing action for pages not indexed.
catalogRecord<string, SeoIssueKind>SEO_ISSUE_CATALOGAccepted for symmetry; the list only counts issues, the checklist reads it.
title / descriptionReactNodebuilt-inHeader.
pageSizenumber8Rows per page.
loading / error / onRetrynoneLoading, failure and retry states.
classNamestringnoneRoot classes.
labelsPartial<SeoPagesLabels>noneStrings.

SeoPageRow

{ id, url, title?, indexStatus: "indexed" | "not-indexed" | "blocked" | "pending", issues: SeoIssue[], vitals?: { LCP?, INP?, CLS? }, lastCrawled? }.

SeoIssueChecklist

PropTypeDefaultDescription
issuesSeoIssue[]required{ id, code, severity, fixed?, detail? }; severity is error, warning or info.
urlstringnoneShown in the header.
onToggleFixed(issue, fixed) => Promise<Result>noneMakes the checkboxes live. Result is void or { error?: string }.
catalogRecord<string, SeoIssueKind>SEO_ISSUE_CATALOGTitles and hints.
titleReactNodebuilt-inHeader.
className / labelsnoneClasses and strings.

Helpers

seoScore(issues) is 100 minus the weighted open issues (SEVERITY_WEIGHT), never below 0. siteScore(pages) averages it. scoreBand(score) gives good, fair or poor. openIssues, issueCounts and sortIssues (most severe first) work on SeoIssue[].

Examples

A checklist next to the preview:

import { SeoIssueChecklist } from "@fadymondy/nasaq/web";

<SeoIssueChecklist url="https://example.com/pricing" issues={issues} onToggleFixed={async (issue, fixed) => { await save(issue.id, fixed); }} />;

Your own issue codes:

import { SeoIssueChecklist } from "@fadymondy/nasaq/web";

<SeoIssueChecklist issues={issues} catalog={{ "missing-hreflang": { severity: "warning", en: { title: "Missing hreflang", why: "Search engines cannot match language versions.", fix: "Add an hreflang link per language." }, ar: { title: "hreflang مفقود", why: "لا تستطيع محركات البحث مطابقة نسخ اللغات.", fix: "أضف رابط hreflang لكل لغة." } } }} />;

Accessibility

KeyAction
TabMove through rows, actions and checkboxes.
SpaceTick or untick an issue.
EnterOpen the row or expand a hint.

The score is a meter with a spoken value and a band word; severity is a word plus an icon, not colour alone.

RTL & i18n

URLs are left-to-right inside the RTL layout. Numbers use Latin digits. Built-in English and Arabic; issue titles in SEO_ISSUE_CATALOG are localised, and labels overrides the rest.

Styling & tokens

Score bands use the success, warning and danger tokens. All spacing is logical.

Do / Don't

  • Do sort worst first by default; teams fix the top of the list.
  • Do give every issue a fix hint.
  • Don't treat the score as a ranking prediction: it is a to-do measure.

Lab

https://docs.nasaqui.com/?path=/docs/components-seo-seo-pages--docs

On this page