Nasaq

Repository picker

Pick a GitHub repository and branch by searching through the app installation, with the official GitHub mark, debounced search, keyboard support and a Configure access link.

PreviewOpen ↗

Code

<RepositoryPicker  account={{ login: "acme" }}  searchRepositories={(q) => api.repos(q)}  loadBranches={(repo) => api.branches(repo.fullName)}  onConfigure={() => window.open("https://github.com/settings/installations")}  onChange={({ repo, branch }) => save(repo?.fullName, branch)}/>

Developer Tools · beta

Live examples and controls: Repository picker in the lab.

Install

npx shadcn@latest add https://docs.nasaqui.com/r/repository-picker.json

Two linked fields: a repository and a branch. Both open a search list. Repositories are searched through the GitHub app installation (the picker only asks your searchRepositories), and picking one loads its branches and selects the default. The footer says whose installation this is and offers "Configure access" for repositories that are not listed. It calls no backend.

When to use

  • Connecting a project, deploy or workflow to a GitHub repository and branch.

When not to use

Import

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

Quick start

<RepositoryPicker
  account={{ login: "acme" }}
  searchRepositories={(q) => api.repos(q)}
  loadBranches={(repo) => api.branches(repo.fullName)}
  onConfigure={() => window.open("https://github.com/settings/installations")}
  onChange={({ repo, branch }) => save(repo?.fullName, branch)}
/>

Anatomy

RepositoryPicker            data-slot="repository-picker"
├─ repository trigger       GitHub mark, owner/name, private lock
├─ branch trigger           default and protected tags
└─ Popover                  search input, listbox of options, error and retry, footer
   └─ footer                installation account, Configure access

API

PropTypeDefaultDescription
value? / defaultValue?{ repo: PickerRepo | null; branch: string | null }emptyControlled or initial value.
onChange?(value) => voidnoneFired on every pick. Picking a repository sets its default branch.
searchRepositories(query) => Promise<PickerRepo[]>requiredCalled with "" when the list opens, then debounced (250 ms) while typing.
loadBranches(repo) => Promise<PickerBranch[]>requiredBranches of the picked repository.
account?{ login, avatar? }noneShown in the footer.
onConfigure?() => voidnoneAdds the "Configure access" button.
hideBranch?booleanfalseRepository only.
disabled?booleanfalse
labels?Partial<RepositoryPickerLabels>en/arOverride any string.

PickerRepo is { id, fullName, description?, private?, language?, defaultBranch?, stars?, updatedAt? }; PickerBranch is { name, default?, protected? }.

Examples

Repository only

<RepositoryPicker hideBranch searchRepositories={search} loadBranches={async () => []} />

Accessibility

  • Each list is a listbox with aria-activedescendant; ArrowUp/ArrowDown move, Enter picks, Escape closes and returns focus to the trigger.
  • Loading, empty and error states are announced; a failed search offers Retry.
  • Private repositories show a lock with a text label, not colour alone.

RTL & i18n

  • English and Arabic built in. owner/name, branch names and language names stay left-to-right in <bdi dir="ltr">.
  • The GitHub mark is the official one from oauth-logos and never mirrors or recolours; it switches to the light artwork on dark themes.

Styling & tokens

  • Uses the Popover, Input and Button tokens; hover --nq-hover. No raw hex.
  • Target [data-slot=repository-picker].

Do / Don't

  • Do debounce on the server side too; the picker only debounces the calls.
  • Do return the defaultBranch on each repo so the first branch loads instantly.
  • Don't pass tokens to the picker; keep them in your searchRepositories.

Lab

https://docs.nasaqui.com/?path=/docs/components-developer-tools-repository-picker--docs

On this page