bootstrap-component
GitHub指导在Bootstrap端口中编写符合规范的TypeScript组件类,涵盖文件结构、类型定义、配置合并、事件处理及Data API实现,确保代码符合严格类型检查和工程标准。
Trigger Scenarios
Install
npx skills add tabler/tabler --skill bootstrap-component -g -y
SKILL.md
Frontmatter
{
"name": "bootstrap-component",
"description": "Write a new Bootstrap-style JavaScript component class in `core\/js\/src\/bootstrap\/` — a `BaseComponent` subclass with typed config, `EVENT_*`\/`CLASS_NAME_*` constants and a `data-bs-toggle` Data API. Use whenever the user asks for a new component in the Bootstrap port (a toggler, a dialog, a chip input, a stepper) or wants an existing one brought up to this baseline. Covers file structure, TypeScript typing of `Default` and `DefaultType`, constructor and config merging, events, the Data API handler and the minimal public API. Not for the build, the tests or the size budget — that is the `core-js` skill."
}
Rules for writing new components
You are a master of JavaScript and TypeScript.
The points below are the baseline for every new component class in core/js/src/bootstrap/. Read the core-js skill first for what that directory is (a vendored port of Bootstrap's JavaScript), how it is built, tested and size-budgeted.
1. File structure
In this order:
- Header with the MIT license comment and the file name (
Bootstrap toggler.ts). - Imports:
BaseComponent,EventHandler, optionallyManipulator,SelectorEngine, helpers from./util/*. - Types and interfaces at the top (
ComponentConfig,ComponentConfigInput). - Constants:
NAME,DATA_KEY,EVENT_KEY, selectors, classes, event names. DefaultandDefaultTypewith TS types.- The component class.
- "Data API implementation" section (when applicable).
- Default export of the class.
2. Typing
-
Define
type ComponentConfigandtype ComponentConfigInput:type ComponentConfig = { attribute: string value: string | number | boolean | null } type ComponentConfigInput = Partial<ComponentConfig> & Record<string, unknown> -
Type
DefaultasComponentConfig. -
Type
DefaultTypeasRecord<keyof ComponentConfig, string>. -
In the class, declare:
declare _element: HTMLElement(or a more specific element type).declare _config: ComponentConfig.declare _isTransitioning: boolean(when needed).
-
Type method signatures explicitly (
show(): void,hide(): void). -
EventHandler.trigger(...)can returnnull— use?.defaultPrevented. -
Use
Eventfor handlers, and cast when you need specifics (const keyboardEvent = event as KeyboardEvent).EventHandler.onis generic, so(event: KeyboardEvent) => …type-checks without a cast; forevent.delegateTargetcast toDelegatedEventfrom./dom/event-handler. -
core/tsconfig.jsonisstrictandcore/js/srchas noanyat all, so a missing null check or an implicitanyfailspnpm run type-check. Reach forunknownplus a type guard, or a small named type, instead ofany,[key: string]: anyoras any. -
Prefer modern syntax like
#privateclass fields over theprivatekeyword.
3. Constructor and config
- Call
super(element, config as Record<string, unknown>). - Read config from
Manipulator.getDataAttributes(...)and merge withDefault.BaseComponent._getConfigalready does this through_mergeConfigObj→_configAfterMerge→_typeCheckConfig. - If you need custom config processing, override
_getConfig(or_configAfterMerge). - After constructing, only set required fields and attach listeners.
4. Events and CSS classes
-
Use constants in the format
EVENT_${NAME}andCLASS_NAME_*. -
Build events with
EVENT_KEYandDATA_KEY(as inalert.ts):const NAME = 'toggler' const DATA_KEY = 'bs.toggler' const EVENT_KEY = `.${DATA_KEY}` const EVENT_TOGGLE = `toggle${EVENT_KEY}` const EVENT_TOGGLED = `toggled${EVENT_KEY}` const CLASS_NAME_SHOW = 'show' -
Fire a cancellable
beforeevent, do the work, then fire theafterevent. -
Use only
EventHandler.on/off/one/trigger.
5. Data API
- Selector in the form
[data-bs-toggle="name"]. The attribute API staysdata-bs-*;data-tblr-*is a 2.0 change (seecore-js). - Data API handler:
- check
A/AREAandevent.preventDefault(). - use
SelectorEngine.getElementFromSelector. Name.getOrCreateInstance(target, config)for data attributes.
- check
- Use the helpers from
./util/component-functionsinstead of writing the handler by hand:eventActionOnPlugin(Component, 'click', SELECTOR_DATA_TOGGLE, 'toggle')for adata-bs-toggle— resolves the targets (data-bs-target/href, or the trigger itself), skips.disabled/:disabled, prevents the default onA/AREA, and calls the method ongetOrCreateInstanceof every target. An optional fifth argument receives{ targets, event, instances }.enableDismissTrigger(Component, 'close')for adata-bs-dismiss.- Write the
EventHandler.on(document, ...)handler yourself only when the trigger needs config from data attributes or other custom logic.
6. Initialization and public API
- Minimal public API:
show,hide,toggle,dispose. - If the component has animation state, use
_queueCallbackand_isAnimated. - Expose
static get NAME,static get Default,static get DefaultType. - Export the class from
core/js/src/bootstrap.ts(named export and thebootstrapnamespace object), otherwise it never ships.
7. Style and consistency
- Keep style consistent with existing components (indentation, naming, comments, the
// Getters/// Public/// Privatesection comments). - Avoid direct DOM operations outside
EventHandlerandSelectorEngine, unless the component requires otherwise.
8. Template
/**
* --------------------------------------------------------------------------
* Bootstrap toggler.ts
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import BaseComponent from './base-component'
import EventHandler from './dom/event-handler'
import { eventActionOnPlugin } from './util/component-functions'
type ComponentConfig = {
attribute: string
value: string | number | boolean | null
}
type ComponentConfigInput = Partial<ComponentConfig> & Record<string, unknown>
/**
* Constants
*/
const NAME = 'toggler'
const DATA_KEY = 'bs.toggler'
const EVENT_KEY = `.${DATA_KEY}`
const EVENT_TOGGLE = `toggle${EVENT_KEY}`
const EVENT_TOGGLED = `toggled${EVENT_KEY}`
const EVENT_CLICK = 'click'
const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="toggler"]'
const DefaultType: Record<keyof ComponentConfig, string> = {
attribute: 'string',
value: '(string|number|boolean)',
}
const Default: ComponentConfig = {
attribute: 'class',
value: null,
}
/**
* Class definition
*/
class Toggler extends BaseComponent {
declare _element: HTMLElement
declare _config: ComponentConfig
constructor(element?: Element | string | null, config?: ComponentConfigInput | null) {
super(element as string | HTMLElement, (config ?? undefined) as Record<string, unknown>)
}
// Getters
static get Default(): ComponentConfig {
return Default
}
static get DefaultType(): Record<keyof ComponentConfig, string> {
return DefaultType
}
static get NAME(): string {
return NAME
}
// Public
toggle(): void {
const toggleEvent = EventHandler.trigger(this._element, EVENT_TOGGLE)
if (toggleEvent?.defaultPrevented) {
return
}
this._execute()
EventHandler.trigger(this._element, EVENT_TOGGLED)
}
// Private
_execute(): void {
const { attribute, value } = this._config
if (attribute === 'class') {
if (value) {
this._element.classList.toggle(String(value))
}
return
}
// Compare as strings since getAttribute() always returns a string
if (this._element.getAttribute(attribute) === String(value)) {
this._element.removeAttribute(attribute)
return
}
this._element.setAttribute(attribute, String(value))
}
}
/**
* Data API implementation
*/
eventActionOnPlugin(Toggler, EVENT_CLICK, SELECTOR_DATA_TOGGLE, 'toggle')
export default Toggler
9. Checklist
- File order as in §1, MIT header with the file name
-
ComponentConfig/ComponentConfigInputdefined;DefaultandDefaultTypetyped -
declare _element/declare _configin the class, explicit return types -
EVENT_*andCLASS_NAME_*constants,?.defaultPreventedon cancellable events - Data API on
[data-bs-toggle="name"]througheventActionOnPlugin(or a hand-written handler with theA/AREAguard andgetOrCreateInstance) - Public API limited to
show/hide/toggle/dispose - Exported from
core/js/src/bootstrap.ts - Spec in
js/tests/unit/, and thecore-jschecklist (type-check, prettier, bundlewatch)
Version History
- 340f719 Current 2026-09-22 21:46


