Skip to content

All TypeScript contracts in Nubisco UI — props, options, enums — live in dedicated .d.ts files. Never inline a type, interface or enum inside a .vue file.

Naming prefixes

Three prefixes make it immediately clear what a symbol is before you look it up:

PrefixMeaningExample
IInterface — describes the shape of an objectISliderProps, IWithMessages
EEnum — a fixed set of named string or numeric valuesESize, EVariant
TType alias — a union, intersection, or primitive aliasTActiveHandle, TJsonValue

This convention applies everywhere: shared types, component types, and documentation-only imports.

Where types live

Types are placed based on how widely they are shared:

src/
  types/           ← shared across multiple components
    Props.d.ts     — base interfaces for all input components
    Size.d.ts      — ESize, ESizeShort, ESizePixel enums
    Variants.d.ts  — EVariant enum
    Option.d.ts    — IOption, IOptionGroup
    Decoration.d.ts

  components/
    Slider.vue
    Slider.d.ts    ← types used only by Slider
    Select.vue
    Select.d.ts    ← types used only by Select

The rule: if two or more components share a type, it belongs in src/types/. If only one component uses it, it lives adjacent to that component as ComponentName.d.ts.

Exports

Always use explicit named exports. No default exports, no re-exporting from index files unless intentional.

ts
// ✓ correct
export { ESize, ESizeShort }

// ✗ avoid
export default ESize

These are the types every component author works with daily. They live in src/types/ and are imported directly from their individual files.

Props hierarchy

All input components build their prop interface by composing these base interfaces rather than redeclaring common fields. The hierarchy:

IDefaultProps
  └── IHumanInputComponent
        └── IFieldComponent
              ├── IWithLabel
              ├── IWithMessages
              └── IWithFieldAppearance
                    └── IReadableFieldComponent

IDefaultProps

The root of every component. Provides the id prop.

ts
/** Any component that can be identified by an explicit DOM id. */
interface IDefaultProps {
  /**
   * Explicit element id.
   * When omitted, a deterministic id is auto-generated by `useStableId()` from the
   * component type and `name` prop — e.g. `nb-text-input-email`.
   */
  id?: string
}

IWithMessages

Adds the three feedback message slots below a field.

ts
/** Components that carry validation / feedback messages below the field. */
interface IWithMessages {
  /** Validation error — takes precedence over `warning` and `helper` when set. */
  error?: string
  /** Non-blocking caution message — shown only when `error` is absent. */
  warning?: string
  /** Contextual hint displayed when neither `error` nor `warning` is set. */
  helper?: string
}

IWithLabel

Adds the visible field label.

ts
/** Components that render a user-visible label. */
interface IWithLabel {
  /** Label text rendered above (`default` variant) or inside (`fluid` variant) the field. */
  label?: string
}

IWithFieldAppearance

Adds variant and size — the two most common presentation props.

ts
/** Components that support the standard field presentation variants and sizes. */
interface IWithFieldAppearance {
  /**
   * Presentation variant:
   * - `default` — label above, message below (standard style).
   * - `fluid`   — label and status icon inside the field box.
   */
  variant?: 'default' | 'fluid'
  /** Control size. */
  size?: 'sm' | 'md' | 'lg'
}

IHumanInputComponent

Extends IDefaultProps with name, disabled, and required.

ts
/**
 * Interactive form control that participates in form submission and can be
 * disabled or marked as required.
 */
interface IHumanInputComponent extends IDefaultProps {
  /**
   * HTML `name` attribute forwarded to the native input.
   * Also drives auto-generated IDs when `id` is omitted:
   * `{component-type}-{name}` — e.g. `nb-select-country`.
   */
  name?: string
  /** Prevents interaction and visually dims the control. */
  disabled?: boolean
  /** Marks the field as mandatory — surfaced in the label and `aria-required`. */
  required?: boolean
}

IFieldComponent

Combines all four mixin interfaces. The baseline for text, number, and select inputs.

ts
/**
 * Full labeled field with placeholder text, validation messages, variant and
 * size. The baseline for text-like, number, and select inputs.
 */
interface IFieldComponent
  extends
    IHumanInputComponent,
    IWithLabel,
    IWithMessages,
    IWithFieldAppearance {
  /** Placeholder text shown when the field has no value. */
  placeholder?: string
}

IReadableFieldComponent

Extends IFieldComponent with a readonly mode.

ts
/**
 * Extends `IFieldComponent` with a read-only mode: the value is visible and
 * copyable but cannot be changed by the user.
 */
interface IReadableFieldComponent extends IFieldComponent {
  /** Makes the field read-only — value is visible but not editable. */
  readonly?: boolean
}

Size enums

ESize covers the full seven-step scale. ESizeShort is the three-step version used by most interactive controls. ESizePixel provides numeric pixel values for icon and image dimensions.

ts
// String-based size tokens (for CSS classes, spacing scales, etc.)
export enum ESize {
  ExtraExtraSmall = 'xxs',
  ExtraSmall = 'xs',
  Small = 'sm',
  Medium = 'md',
  Large = 'lg',
  ExtraLarge = 'xl',
  ExtraExtraLarge = 'xxl',
}
ts
export enum ESizeShort {
  Small = 'sm',
  Medium = 'md',
  Large = 'lg',
}
ts
// Numeric size values in pixels (for icons, images, components with fixed dimensions)
export enum ESizePixel {
  ExtraExtraSmall = 8,
  ExtraSmall = 12,
  Small = 14,
  Medium = 16,
  Large = 20,
  ExtraLarge = 60,
  ExtraExtraLarge = 92,
}

Variant enum

ts
enum EVariant {
  Primary = 'primary',
  Secondary = 'secondary',
  Ghost = 'ghost',
  Danger = 'danger',
  Success = 'success',
  Warning = 'warning',
}

Option types

IOption and IOptionGroup are used by any component that renders a list of selectable items — Select, Radio, and others.

ts
interface IOption extends IDecoration {
  id?: number | string
  label?: string
  name?: string
  value?: string | number
  color?: string
  context?: string
  i18n_key?: string
  createdBy?: number | string
  createdAt?: string
  disabled?: boolean
  tooltip?: string
  unformatted?: boolean
  code?: string
  hidden?: boolean
}
ts
interface IOptionGroup {
  groupName?: string // Optional: Name of the group
  options: IOption[]
}

Every component that exposes a public API has an adjacent .d.ts file with the same name. These files contain everything that isn't shared: the component's own prop interface, any enums specific to its behaviour, and internal types that are worth making visible to consumers.

File structure

src/components/
  Button.vue
  Button.d.ts    ← EButtonType, IButtonProps
  Select.vue
  Select.d.ts    ← ESelectStatus, ISelectProps
  Slider.vue
  Slider.d.ts    ← ISliderProps, TActiveHandle

Composing from shared types

Component prop interfaces extend the shared base interfaces rather than redeclaring common props:

ts
// src/components/TextInput.d.ts
import { IReadableFieldComponent } from '@/types/Props.d'

interface ITextInputProps extends IReadableFieldComponent {
  /** Maximum character count. Shows a counter when set. */
  maxLength?: number
}

export { ITextInputProps }

This keeps intellisense descriptions centralised — a change to IWithMessages propagates to every component that extends IFieldComponent.

Adding regions for documentation

Any part of a .d.ts file can be pulled directly into a documentation page using VitePress's code snippet import with a named region. Mark the region with #region / #endregion comments:

ts
// #region EAiLabelSize
enum EAiLabelSize {
  Small = 'sm',
  Medium = 'md',
  Large = 'lg',
}
// #endregion EAiLabelSize

Then inline it in a markdown page:

md
\<<< @../../src/components/AiLabel.d.ts#EAiLabelSize

TIP

Name the region after the symbol it wraps. This makes it self-documenting and easy to target from multiple pages if needed.

Region names are case-sensitive and must be unique within a file. A single symbol can only belong to one region.