ComponentsFeedback

Duplicate notice

A row that appears under a Company you just saved when Ascern finds one that looks the same. It points it out and never blocks the save.

Playground

Change the controls to try each prop. The code under the preview updates as you go and lists only the props you changed; copy it into your page.

Halcyon: possible duplicate ofHalcyon Bank(same website, similar name)Open Halcyon Bank
import { DuplicateNotice } from '@/ui/duplicate-notice';<DuplicateNotice name="Halcyon" />

In the table

Right under the row that was saved, full width, on the sunken fill. It stays until dismissed or the value changes. Press × to dismiss it, then Replay to save again.

CompanyWebsiteOwner
Orbital Freightorbitalfreight.comPriya Shah
Halcyonhalcyonbank.comPriya Shah
Halcyon: possible duplicate ofHalcyon Bank(same website, similar name)Open Halcyon Bank
Brightwave Paymentsbrightwave.ioTom Lindqvist
import { useState, type CSSProperties } from 'react';
import { Button } from '@/ui/button';
import { DuplicateNotice } from '@/ui/duplicate-notice';
import { moveList } from '@/ui/motion';

const row = 'grid h-10 grid-cols-3 items-center border-b border-border px-150 text-body leading-body';
const listRow = (name: string) => ({ 'data-list-row': '', style: { '--list-row': name } as CSSProperties });

// Halcyon was just saved with halcyonbank.com. Press × to dismiss the notice, then Replay to save again.
export default function DuplicateNoticeTable() {
  const [shown, setShown] = useState(true);
  return (
    <div className="flex w-full flex-col items-start gap-200">
      <div className="w-full overflow-hidden rounded-large inset-ring inset-ring-border">
        <div className={`${row} font-medium text-text-subtle`}>
          <span>Company</span>
          <span>Website</span>
          <span>Owner</span>
        </div>
        <div className={row} {...listRow('orbital')}>
          <span className="font-medium text-text">Orbital Freight</span>
          <span className="text-text">orbitalfreight.com</span>
          <span className="text-text-subtle">Priya Shah</span>
        </div>
        <div className={row} {...listRow('halcyon')}>
          <span className="font-medium text-text">Halcyon</span>
          <span className="text-text">halcyonbank.com</span>
          <span className="text-text-subtle">Priya Shah</span>
        </div>
        {shown ? (
          <DuplicateNotice
            name="Halcyon"
            matches={[{ name: 'Halcyon Bank', reasons: 'same website, similar name', href: '#halcyon-bank' }]}
            onDismiss={() => setShown(false)}
          />
        ) : null}
        <div className={row} {...listRow('brightwave')}>
          <span className="font-medium text-text">Brightwave Payments</span>
          <span className="text-text">brightwave.io</span>
          <span className="text-text-subtle">Tom Lindqvist</span>
        </div>
      </div>
      <Button size="sm" disabled={shown} onClick={(event) => moveList(() => setShown(true), event.currentTarget)}>
        Replay
      </Button>
    </div>
  );
}

Several matches

One notice per saved row, listing each match once with all its reasons.

Brightwave: possible duplicate ofBrightwave Payments(same LinkedIn page, similar name)Open Brightwave PaymentsCông ty Brightwave Việt Nam(similar name)Open Công ty Brightwave Việt Nam
import { DuplicateNotice } from '@/ui/duplicate-notice';

// Each match once, with all its reasons. Names show as stored, in any script.
export default function DuplicateNoticeSeveral() {
  return (
    <DuplicateNotice
      className="w-full"
      name="Brightwave"
      matches={[
        { name: 'Brightwave Payments', reasons: 'same LinkedIn page, similar name', href: '#brightwave-payments' },
        { name: 'Công ty Brightwave Việt Nam', reasons: 'similar name', href: '#brightwave-vn' },
      ]}
      onDismiss={() => {}}
    />
  );
}

On this page