Nasaq
Components

DomainsManager

Custom domains for a site - add a domain, see its DNS check state, check again, make one primary, remove with a confirm, with the CNAME target to copy. Also DomainChips, compact chips with a +N overflow chip.

PreviewOpen ↗

Code

import { DomainsManager, type DomainRecord } from "@fadymondy/nasaq/web";declare const domains: DomainRecord[];declare const api: { add(h: string): Promise<void>; remove(id: string): Promise<void>; recheck(id: string): Promise<void> };export const Domains = () => (  <DomainsManager    domains={domains}    cnameTarget="edge.example.com"    onAdd={(host) => api.add(host)}    onRemove={(id) => api.remove(id)}    onRecheck={(id) => api.recheck(id)}  />);

Server Tools · beta

Live examples and controls: DomainsManager in the lab.

Install

npx shadcn@latest add https://docs.nasaqui.com/r/domains-manager.json

Connect custom domains. The add form normalises what people paste (scheme, path, case), the CNAME target they must point at is shown with a copy button, and each domain row shows its check (verified, pending, checking, failed) with the reason when it failed. Row actions: check again, make primary, remove (with a confirm). DomainChips is the compact version for tables and cards: it shows up to three domains as chips and a "+N more" chip that opens the rest. It has no backend: your callbacks talk to the server and you pass the updated domains back.

When to use

  • A site or project settings page with custom domains.
  • DomainChips inside a table cell that lists domains.

When not to use

  • Editing DNS records of a zone: use DnsManagement.
  • Domain purchase or registrar flows.

Import

import { DomainsManager } from "@fadymondy/nasaq/web";
// inside this monorepo: "@nasaq/web"

Quick start

import { DomainsManager, type DomainRecord } from "@fadymondy/nasaq/web";

declare const domains: DomainRecord[];
declare const api: { add(h: string): Promise<void>; remove(id: string): Promise<void>; recheck(id: string): Promise<void> };

export const Domains = () => (
  <DomainsManager
    domains={domains}
    cnameTarget="edge.example.com"
    onAdd={(host) => api.add(host)}
    onRemove={(id) => api.remove(id)}
    onRecheck={(id) => api.recheck(id)}
  />
);

Anatomy

DomainsManager               data-slot="domains-manager"
├─ summary Badge             "2 of 4 verified"
├─ add form                  hostname Input + Add
├─ CNAME target              value with CopyButton
└─ DataTable                 domain (+ Primary badge), check Status (+ error), added; row menu: Check again, Make primary, Remove

DomainChips                  data-slot="domain-chips"
├─ chip x up to 3            host + check state
└─ "+N" chip                 Popover with the rest

API

DomainsManager: every Card prop except children, plus:

PropTypeDefaultDescription
domainsreadonly DomainRecord[]required{ id, host, check, primary?, addedAt?, error? }. Check: verified, pending, checking, failed.
cnameTargetstringThe CNAME people point at. Shown with a copy button.
loadingbooleanfalseSkeleton state.
onAdd(host) => Promise<void | { error? }>requiredHost is already normalised. Resolve { error } to show it under the field.
onRemove(id) => Promise<...>requiredRuns after the confirm.
onRecheck(id) => Promise<...>requiredRun the DNS check again, then update check.
onMakePrimary(id) => Promise<...>Shows Make primary.
labelsPartial<DomainsManagerLabels>Override any string.

DomainChips: domains ({ id, host, check, primary? }[]), max (default 3), labels, and every ul prop.

Helpers (pure, tested): normalizeHost, isValidHostname(host, { wildcard }), summarizeDomains, splitOverflow(items, max) (never hides just one).

Examples

Chips in a table cell

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

export const Cell = () => (
  <DomainChips domains={[{ id: "1", host: "shop.example.com", check: "verified", primary: true }]} />
);

Accessibility

  • A check state is an icon and a word. Errors from callbacks appear under the field with role="alert".
  • Remove opens an AlertDialog. The "+N more" chip is a button with a name and opens a Popover with the list.
  • The row menu is also a button in the row, not only right-click.

RTL & i18n

  • English and Arabic strings follow the Nasaq locale. Hostnames and the CNAME value stay left to right in their own isolate.

Styling & tokens

  • Built on Card, DataTable, Status, Badge, Popover, AlertDialog and --nq-* tokens. Target [data-slot="domains-manager"].

Do / Don't

  • Do show why a check failed (error).
  • Do tell people the CNAME target before they add the domain.
  • Don't let people remove the primary domain without making another one primary first.
  • Don't trust the input: validate the host again on the server.

Lab

https://docs.nasaqui.com/?path=/docs/components-server-tools-domains-manager--docs

On this page