Skip to content

For AI Agents

BPL DS is definition-first: HTML is the API. There are no React wrappers, no component frameworks, no JavaScript required for purely visual components. Every component is expressed in three parts:

  1. HTML shape — the exact markup structure, using semantic elements and BEM class names.
  2. Public CSS API — custom properties prefixed --<component>-* that consumers override to customize appearance.
  3. State contract — ARIA attributes and native HTML state (:checked, [open], [disabled]) that CSS reads directly; JS only writes to the DOM, never applies style classes.

ResourceURL
Agent contract (AGENTS.md)https://ds.bepartnerlabs.com/AGENTS.md
Programmatic registryhttps://ds.bepartnerlabs.com/registry/components.json
Individual component docshttps://ds.bepartnerlabs.com/components/<name>/

Fetch AGENTS.md first. It is the authoritative machine-readable contract for every component.


Every CSS custom property in BPL DS follows a three-level resolution chain. This pattern is described in detail at Custom Properties with Defaults.

Level 1 — Design token --bp-color-primary: #0055ff;
Level 2 — Component token --btn-bg: var(--bp-color-primary);
Level 3 — Private variable --_bg: var(--btn-bg, #0055ff);

How it resolves for .bp-btn:

/* Level 1: global design token */
:root {
--bp-color-primary: #0055ff;
}
/* Level 2: component token (consumer API) */
/* consumers override this to retheme a single component */
/* --btn-bg: var(--bp-color-primary); */
/* Level 3: private variable on the root selector only */
.bp-btn {
--_bg: var(--btn-bg, var(--bp-color-primary, #0055ff));
background-color: var(--_bg);
}

Correct customization — use the component token in your own CSS:

/* ✅ base state */
.my-cta {
--btn-bg: var(--bp-color-success);
--btn-color: #ffffff;
}
/* ✅ hover state — reuse the same token, different value */
.my-cta:hover {
--btn-bg: var(--bp-color-success-hover);
}
<!-- apply your class alongside the BPL DS class -->
<button class="bp-btn my-cta">Get started</button>

The component’s internal :hover rule reads --_bg which resolves --btn-bg — so redefining --btn-bg in your own :hover selector overrides it cleanly. No new tokens needed.

Never override --_* private variables — they are internal and may change without notice.


Components respond to their container width, not the viewport. This lets the same component work inside a sidebar, a modal, or a full-width section without changes.

/* ✅ correct: container query */
@container (min-width: 40rem) {
.bp-card {
flex-direction: row;
}
}
/* ❌ wrong: media query inside a component */
@media (min-width: 40rem) {
.bp-card {
flex-direction: row;
}
}

Exception: layout primitives that span the full viewport (e.g., the grid, the page shell) may use media queries because their container is the viewport.


All BPL DS rules are placed in named @layer blocks. This makes specificity predictable: any unlayered CSS (or a higher-priority layer) wins over DS styles automatically.

@layer bp-tokens, bp-reset, bp-grid, bp-components, bp-utilities;
LayerWins overLoses to
bp-tokenseverything above it
bp-resetbp-tokensbp-grid and above
bp-gridbp-reset and belowbp-components and above
bp-componentsbp-grid and belowbp-utilities and above
bp-utilitiesall DS layersunlayered CSS

To override DS styles, place your rules in bp-utilities or outside any @layer block entirely. Never edit the DS layer files directly.


The BPL DS grid uses four named zones. Every direct child of .bp-content-grid is placed in the content zone by default; add a modifier class to opt into a wider zone.

ZoneWidthClass on child
content~72 rem(default, no class needed)
popout~60 rem.popout
breakout~90 rem.breakout
full-width100 vw.full-width

HTML usage:

<div class="bp-content-grid">
<p>Default content-width paragraph.</p>
<figure class="breakout">
<img src="wide-image.jpg" alt="A breakout image" />
</figure>
<div class="full-width">
<nav>Full-viewport navigation bar</nav>
</div>
</div>

Public API tokens (set on .bp-content-grid or a parent class):

  • --content-max-width — max width of the content zone (default: 72rem)
  • --popout-max-width — max width of the popout zone (default: 60rem)
  • --breakout-max-width — max width of the breakout zone (default: 90rem)
  • --padding-inline — horizontal gutter (default: clamp(1.25rem, 1vw + 1rem, 2rem))

Client implementations can replace the --bp- prefix with their own brand prefix. This enables full white-labeling without touching any component CSS.

What you can replace:

ScopeHow
Base tokens (--bp-* on :root)Map your client tokens to the --bp-* surface in your own :root
Grid tokens (--padding-inline, --content-max-width, etc.)Override directly — no prefix, already your public API

What you must NOT replace:

ScopeWhy
Component public tokens (--btn-*, --input-*, etc.)Override per-component via the 3-level pattern, not globally
Private vars (--_*)Internal — never touch

Pattern:

/* Map your brand tokens to the bp- surface */
:root {
--bp-primary: var(--acme-brand-500);
--bp-primary-fg: var(--acme-white);
--bp-color-bg: var(--acme-neutral-100);
}

Every component picks up the new values automatically through the 3-level chain — no component CSS changes required.


Copy and paste this prompt at the start of any AI session that involves BPL DS:

You are working with BPL DS, a definition-first design system.
Step 1: fetch https://ds.bepartnerlabs.com/AGENTS.md and read it fully before writing any code.
Rules you must follow:
1. HTML is the API — use the exact markup structure from AGENTS.md. No framework wrappers.
2. Customize only via component tokens (--<component>-*) in your own CSS class, never via inline styles or private (--_*) variables.
3. State is ARIA / native HTML — CSS reads [aria-selected], [open], :checked, :disabled. JS only writes attributes, never toggles style classes.
4. Use container queries inside components, not media queries. Exception: full-viewport layout primitives.
5. Place overrides in bp-utilities layer or outside any @layer to guarantee they win.
Task: [describe what you want to build]