@bfrs/agentic-components
v0.8.0
Published
Shiprocket agentic component library and documentation showcase.
Keywords
Readme
Agentic Components
Production-grade component library for Shiprocket agentic interfaces. React consumers use the native React exports; Angular consumers use the packaged Custom Elements bridge.
- Repository: https://github.com/bfrs/agentic-components
- Showcase: https://agentic-components.vercel.app/
- Package:
@bfrs/agentic-components
Install
Install from the public npm registry:
npm install @bfrs/agentic-componentsDuring install, the package writes BFRS_AGENTIC_COMPONENTS.md into the consuming project. It also ensures AGENTS.md and CLAUDE.md reference that file, creating either file when missing. Existing agent files are preserved and only receive the reference line:
Use BFRS_AGENTIC_COMPONENTS.md for knowledge regarding the component library.The same install hook also wires the shared BFRS lint guard into the consumer package:
{
"scripts": {
"check:bfrs-agentic-lint": "bfrs-agentic-lint all",
"build": "bfrs-agentic-lint all && ..."
}
}The guard fails builds when app code bypasses the component library, uses raw color tokens, defines local components with library names, or overrides library styling through raw tag selectors, :has(), .bfrs-* / Emotion / Radix internals, structural attributes, library token declarations, or !important. Set BFRS_AGENTIC_COMPONENTS_SKIP_SETUP=1 during install to skip automatic docs and lint script setup.
React Usage
import "@bfrs/agentic-components/styles";
import { BfrsProvider, Button, Card, Checkbox, Input, Text } from "@bfrs/agentic-components";
export function Example() {
return (
<BfrsProvider>
<Card>
<Text variant="title">Create shipment</Text>
<Input placeholder="Pickup pincode" />
<Checkbox label="Save this pickup address" defaultChecked />
<Button onClick={() => undefined}>Continue</Button>
</Card>
</BfrsProvider>
);
}The stylesheet is safe to import globally: it does not ship Tailwind preflight, page-level resets, global font-face declarations, unprefixed utilities, or generic keyframes. React surfaces should still render inside BfrsProvider; the provider owns --bfrs-* theme variables and passes the same scope to Radix portals.
Optional: bundled SF Pro font
The main stylesheet only references the SF Pro family by name (--bfrs-font-sans) — it ships no font files, so by default you supply the font. To have the library download and apply SF Pro across your whole app, additionally import the opt-in font stylesheet once at your entry point:
import "@bfrs/agentic-components/styles";
import "@bfrs/agentic-components/fonts.css";This bundles the SF Pro Display webfont (relative URLs, so any base path works), defines --bfrs-font-sans at the document root, and applies it to html, body. Keeping it separate means the main stylesheet stays free of global @font-face/html/body rules.
Most DOM-backed components forward compatible React props such as onClick, onKeyDown, aria-*, data-*, className, style, and refs. Controlled components expose explicit callbacks such as onValueChange, onOpenChange, onSort, onRowClick, and onPageChange.
Library-owned Tailwind utilities are prefixed with bfrs-, for example bfrs-flex, hover:bfrs-bg-primary, and bfrs-animate-shimmer. Unprefixed classes passed through className are treated as host-app classes.
Size-aware controls support xs, sm, md, and lg where applicable. Text inputs and select-family triggers render at the Figma 28px field height; button-like controls keep their own compact scale by component family.
Angular Usage
Angular apps should import the custom element registry once and include the shared stylesheet globally:
// main.ts
import "@bfrs/agentic-components/custom-elements";/* styles.scss */
@import "@bfrs/agentic-components/styles";
/* Optional — bundled SF Pro, applied to the whole app: */
@import "@bfrs/agentic-components/fonts.css";If Angular does not resolve the package style export, add the built CSS files in angular.json:
{
"styles": [
"node_modules/@bfrs/agentic-components/dist/style.css",
"node_modules/@bfrs/agentic-components/dist/fonts.css",
"src/styles.scss"
]
}Add CUSTOM_ELEMENTS_SCHEMA to the module or standalone component that renders the tags:
import { CUSTOM_ELEMENTS_SCHEMA, Component } from "@angular/core";
@Component({
selector: "app-example",
standalone: true,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `
<bfrs-input label="Pickup pincode" (value-change)="pickup = $event.detail.value"></bfrs-input>
<bfrs-button variant="primary" (click)="continue()">Continue</bfrs-button>
`
})
export class ExampleComponent {
pickup = "";
continue() {}
}Use native Angular DOM event bindings for interactions. Do not pass React-style onClick in Angular templates:
<bfrs-button variant="primary" (click)="continue()">Continue</bfrs-button>
<bfrs-paper (click)="openDetails()">Open details</bfrs-paper>The custom-elements entrypoint registers Angular-friendly tags for the documented component surface, including layout, forms, feedback, overlays, filters, data display, navigation, and agentic pattern components.
Use simple attributes for primitive values and [props] for structured values or callback-capable advanced props:
<bfrs-select
placeholder="Channel"
[props]="{ options: channelOptions, value: channel }"
(value-change)="channel = $event.detail.value">
</bfrs-select>
<bfrs-data-table
[props]="{ data: orders, columns: orderColumns, selection: true }"
(cell-action)="handleTableAction($event.detail)"
(row-click)="openOrder($event.detail.row)"
(sort-change)="sorting = $event.detail.sorting">
</bfrs-data-table>For DataTable action cells in Angular, use serializable column configs instead of React cell functions:
orderColumns = [
{ id: "orderId", header: "Order ID", accessorKey: "orderId" },
{
id: "actions",
header: "Actions",
cellType: "buttons",
actions: [
{ id: "view", label: "View", variant: "outline", size: "sm", iconName: "eye" },
{ id: "ship", label: "Ship now", variant: "primary", size: "sm", disabledKey: "shipDisabled" }
]
}
];Rich Angular/HTML cells use the same serializable column approach. Supported
cellType values are text, chip, chips, badge, badges, image,
avatar, link, custom-element, button, buttons, and actions.
orderColumns = [
{
id: "status",
header: "Status",
accessorKey: "status",
cellType: "chip",
cellConfig: { caption: "Current status", labelKey: "status", toneKey: "statusTone" }
},
{
id: "channel",
header: "Channel",
cellType: "image",
cellConfig: { srcKey: "channelLogo", altKey: "channelName", width: 32, height: 32 }
},
{
id: "customer",
header: "Customer",
cellType: "custom-element",
cellConfig: {
tagName: "customer-summary",
attributeMap: { name: "customer.name", email: "customer.email" },
events: ["open"]
}
}
];Registered custom-element events are re-emitted by bfrs-data-table as
cell-event with { eventName, detail, columnId, row, rowId, rowIndex }.
ReactNode props are exposed to Angular as native named slots. Slotted Angular components remain live; they are not converted to static HTML:
<bfrs-page-header title="Orders">
<bfrs-breadcrumbs slot="breadcrumb" [props]="{ items: breadcrumbs }"></bfrs-breadcrumbs>
<bfrs-button slot="secondary-actions" variant="outline">Export</bfrs-button>
<bfrs-button slot="actions">Create order</bfrs-button>
</bfrs-page-header>
<bfrs-workspace-header toggle (toggle-sidebar)="toggleSidebar()">
<app-brand slot="brand"></app-brand>
<app-workspace-tabs slot="tabs"></app-workspace-tabs>
<app-global-search slot="search"></app-global-search>
<app-user-actions slot="actions"></app-user-actions>
</bfrs-workspace-header>Common named slots include left-icon, right-icon, label, helper-text,
error-message, trigger, title, description, footer, actions,
primary-action, secondary-actions, search-input, filter-trigger,
breadcrumb, header, sidebar, brand, tabs, search, icon,
empty-state, error, and row-actions-header.
Tabs accept serializable items and live slots using the convention
tab-{value}-label, tab-{value}-badge, and tab-{value}-content:
<bfrs-tabs [props]="{ items: [{ value: 'open', label: 'Open' }, { value: 'closed', label: 'Closed' }] }">
<bfrs-badge slot="tab-open-badge" count="4"></bfrs-badge>
<app-open-orders slot="tab-open-content"></app-open-orders>
<app-closed-orders slot="tab-closed-content"></app-closed-orders>
</bfrs-tabs>Angular can also use the compound API directly:
<bfrs-tabs value="open" (value-change)="activeTab = $event.detail.value">
<bfrs-tabs-list>
<bfrs-tabs-trigger value="open">Open <bfrs-badge slot="badge" count="4"></bfrs-badge></bfrs-tabs-trigger>
<bfrs-tabs-trigger value="closed">Closed</bfrs-tabs-trigger>
</bfrs-tabs-list>
<bfrs-tabs-content value="open"><app-open-orders></app-open-orders></bfrs-tabs-content>
<bfrs-tabs-content value="closed"><app-closed-orders></app-closed-orders></bfrs-tabs-content>
</bfrs-tabs>For imperative notifications, mount one provider and call its public methods
through ViewChild:
<bfrs-toast-provider #toasts placement="bottom-center"
(toast-action)="handleToastAction($event.detail)">
</bfrs-toast-provider>@ViewChild("toasts") toasts!: ElementRef<HTMLElement & {
success(input: string | { title: string; description?: string }): string;
danger(input: string | { title: string; description?: string }): string;
dismiss(id: string): void;
clear(): void;
}>;
save() {
this.toasts.nativeElement.success("Order saved");
}DataTable also accepts declarative leadingColumn, rowActions,
rowClassRules, rowIdKey, accessorPath, and sortValueKey configuration.
The default table chrome matches Shiprocket 4.0 Figma: 8px outer radius, strong #D3DFD7 outer/header stroke, 38px header, 64px rows, 12px text, 12px selection checkboxes, and a 146px sticky actions column headed Actions.
The standalone helpers are available as bfrs-table-toolbar,
bfrs-table-empty-state, bfrs-table-error-state, bfrs-table-skeleton,
bfrs-table-row-actions, bfrs-table-bulk-actions, and
bfrs-table-column-visibility, plus bfrs-table-save-view.
For custom Angular table layouts where bfrs-data-table is too prescriptive,
use the primitive table tags: bfrs-table, bfrs-thead, bfrs-tbody,
bfrs-tfoot, bfrs-tr, bfrs-th, and bfrs-td.
Registered tags include bfrs-box, bfrs-container, bfrs-paper, bfrs-stack, bfrs-grid, bfrs-text, bfrs-icon, bfrs-button, bfrs-button-group, bfrs-icon-button, bfrs-form-field, bfrs-label, bfrs-input, bfrs-slider, bfrs-color-picker, bfrs-color-swatch-group, bfrs-textarea, bfrs-select, bfrs-date-range-picker, bfrs-searchable-select, bfrs-multi-select, bfrs-tag-input, bfrs-suggest-input, bfrs-option-card-group, bfrs-selectable-chip-group, bfrs-number-stepper, bfrs-file-dropzone, bfrs-reveal-field, bfrs-checkbox, bfrs-radio, bfrs-switch, bfrs-badge, bfrs-chip, bfrs-alert, bfrs-info-card, bfrs-tip, bfrs-toast-manager, bfrs-toast-provider, bfrs-spinner, bfrs-skeleton, bfrs-empty-state, bfrs-error-state, bfrs-loading-state, bfrs-modal, bfrs-drawer, bfrs-confirm-dialog, bfrs-dropdown, bfrs-tooltip, bfrs-popover, bfrs-avatar, bfrs-metric-card, bfrs-table-pagination, bfrs-table-toolbar, bfrs-table-empty-state, bfrs-table-error-state, bfrs-table-skeleton, bfrs-table-row-actions, bfrs-table-bulk-actions, bfrs-table-column-visibility, bfrs-table-save-view, bfrs-data-table, bfrs-table, bfrs-thead, bfrs-tbody, bfrs-tfoot, bfrs-tr, bfrs-th, bfrs-td, bfrs-tabs, bfrs-tabs-list, bfrs-tabs-trigger, bfrs-tabs-content, bfrs-breadcrumbs, bfrs-action-menu, bfrs-page-header, bfrs-section-header, bfrs-layout-shell, bfrs-form-section, bfrs-filter-bar, bfrs-filter-drawer, bfrs-chat-bubble, bfrs-chat-composer, bfrs-full-page-loader, bfrs-business-info-display-card, bfrs-collapsible, bfrs-accordion, bfrs-summary-bar, bfrs-entity-display-card, bfrs-reveal-and-copy, bfrs-horizontal-stepper, and bfrs-step-progress-card.
HorizontalStepper provides the compact horizontal flow layout with an optional announcement banner and parent-owned onClose / onStepSelect behavior:
import { HorizontalStepper } from "@bfrs/agentic-components";
<HorizontalStepper
announcement="Great Choice! Early COD Remittance activation in progress.."
closeButton
onClose={handleClose}
currentStep={0}
title="Select a Plan"
subheading="Get guaranteed remittance from the shipment delivered date."
size="sm"
variant="primary"
steps={[
{ label: "Select Plan", secondaryText: "Choose payout speed" },
{ label: "Verify OTP", secondaryText: "Confirm activation" }
]}
/>Use variant="primary" | "success" | "info" | "warning" | "neutral" for semantic color treatment, and size="sm" | "md" for compact or roomier layouts.
Theme Overrides
The package exposes a framework-neutral theme helper for scoped token overrides. Use it from React, Angular, or plain TypeScript without importing the React component entry:
import { applyAgenticTheme } from "@bfrs/agentic-components/theme";
applyAgenticTheme({
colors: {
primary: "#5B45C2",
primaryHover: "#4C35AE",
primarySoft: "#F1ECFB",
borderFocus: "#5B45C2"
},
radius: {
control: "14px",
card: "18px"
},
shadows: {
card: "0 12px 32px rgb(91 69 194 / 0.16)"
}
});applyAgenticTheme() writes to an explicit target when provided, otherwise to the first mounted BFRS scope (.bfrs, [data-bfrs-root], or [data-bfrs-mount]). It never writes to the host document root. The helper accepts hex, rgb, hsl, or raw HSL channel values for semantic color tokens. Plain CSS variable overrides also work on a BFRS scope:
.bfrs {
--bfrs-color-primary: 251 51% 52%;
--bfrs-radius-control: 14px;
--bfrs-shadow-card: 0 12px 32px rgb(91 69 194 / 0.16);
}BfrsProvider also accepts theme and colorScheme="light" | "dark" props. Inline style values override generated theme variables when both are provided.
Validated Forms
Keep form validation and API checks in the app. Render field errors below inputs, then show success or failure through the toast API.
<FormField label="Pickup pincode" errorText={errors.pickupPincode}>
<Input error={Boolean(errors.pickupPincode)} value={pickupPincode} onChange={updatePickupPincode} />
</FormField><bfrs-input
label="Pickup pincode"
[value]="pickupPincode"
[attr.error]="errors.pickupPincode ? true : null"
[attr.error-message]="errors.pickupPincode || null"
(value-change)="pickupPincode = $event.detail.value">
</bfrs-input>
<bfrs-toast-manager [props]="{ toasts: toasts }" (dismiss)="dismissToast($event.detail.id)"></bfrs-toast-manager>DateRangePicker
Use DateRangePicker for preset and custom date-range filters. Keep API date formatting in the consuming app.
The trigger uses the neutral compact secondary control by default so it aligns with filter bar dropdowns.
import { DateRangePicker, presetToRange, type DateRangeValue } from "@bfrs/agentic-components";
const [range, setRange] = useState<DateRangeValue>({
preset: "Last 30 days",
...presetToRange("Last 30 days")
});
<DateRangePicker value={range} onChange={setRange} maxRangeDays={365} />;ToastProvider
Wrap the app once and call toast helpers from app event handlers.
import { Button, ToastProvider, useToast } from "@bfrs/agentic-components";
function SaveButton() {
const { success, danger } = useToast();
return <Button onClick={() => success("Changes saved")}>Save</Button>;
}
<ToastProvider>
<SaveButton />
</ToastProvider>;Checkbox
Use Checkbox for independent true/false decisions or multi-select choices. It renders as a square checklist control, while Radio renders circular options for single-choice groups. Both support primary text plus secondary description text.
The default checkbox is the compact 12px Shiprocket 4.0 control with secondary stroke and 2.5px radius.
import { Checkbox, Radio } from "@bfrs/agentic-components";
<Checkbox
label="Accept terms"
description="Use checkboxes when each option can be selected independently."
checked={accepted}
onCheckedChange={setAccepted}
/>
<Checkbox label="Partially selected" checked="indeterminate" />
<Radio
options={[
{ value: "registered", label: "Registered business", description: "Company GST and business KYC are available." },
{ value: "individual", label: "Individual seller", description: "Use personal details for seller verification." }
]}
defaultValue="registered"
/>Development
npm run typecheck
npm run lint
npm run build:lib
npm run build:demonpm run build:lib outputs the package to dist.
npm run build:demo outputs the showcase app to dist-demo.
Publishing
Package publishing is configured for npmjs public packages. Publish only through the controlled release flow:
npm run changeset
npm run version-packages
git tag v0.1.0
git push origin main --tagsThe Publish Package GitHub Action publishes to npmjs on version tags, published GitHub releases, or manual workflow dispatch. Configure the repository secret NPM_TOKEN with publish access.
Showcase Deployment
The public documentation is hosted at https://agentic-components.vercel.app/.
The showcase build target is dist-demo:
npm run build:demo