@dloizides/ui-forms

中文文档
1.38.0发布于 2026/11/12MITTypeScriptESM + CJS近 30 天下载 5794

Themable, brand-agnostic React Native (RN-web) form components — FormField, ChipSelector, FormSwitch — sharing the @dloizides/ui-feedback UI context. Part of the dloizides.com shared UI kit.

原始使用文档
文档目录8 节
  1. Install
  2. Usage
  3. Field — label any control, not just a text input
  4. ChipSelector
  5. Dense controls — SelectControl / TypeaheadControl / DateRan…
  6. Every string is pre-localized
  7. testIDs
  8. License

@dloizides/ui-forms

Themable, brand-agnostic React Native (RN-web) form components for the dloizides.com portfolio: Field, FormField, ChipSelector, FormSwitch. They read theme colours from the shared @dloizides/ui-feedback UI context (useUi) — mount one UiProvider / FeedbackUiProvider at your app root and these components pick up your theme automatically.

Install

npm install @dloizides/ui-forms @dloizides/ui-feedback

Peer dependencies: @dloizides/ui-feedback >= 1.1.0, react >= 18, react-native >= 0.74 (use react-native-web on web).

Usage

import { FormField, ChipSelector, FormSwitch } from '@dloizides/ui-forms';

<FormField label="Email" required error={errors.email} value={email} onChangeText={setEmail} />
<ChipSelector label="Plan" options={plans} value={plan} onChange={setPlan} />
<FormSwitch label="Email notifications" value={notify} onValueChange={setNotify} />

Field — label any control, not just a text input

FormField is hard-wired to a text input. For any other control — a dropdown, a date picker, a chip selector — wrap it in Field to get the identical label row, required mark, error line and bottom spacing. This is what keeps a dropdown aligned with the FormField next to it: without it the dropdown's box starts a label-row higher and the row loses its vertical rhythm.

import { Field } from '@dloizides/ui-forms';

<Field label="Currency" required error={errors.currency}>
  <ModalDropdown options={currencies} value={currency} onChange={setCurrency} />
</Field>

FormField and ChipSelector compose Field internally, so the label row can never drift out of alignment between them — there is exactly one label implementation in the kit.

To wire the error line into a custom control's own aria-describedby / invalid state, pass a function child — it receives { describedById, hasError } (describedById is undefined when there is no error):

<Field label="Country" error={errors.country}>
  {({ describedById, hasError }) => (
    <CountryPicker aria-describedby={describedById} hasError={hasError} value={country} onChange={setCountry} />
  )}
</Field>
PropTypeNotes
labelstringoptional — an absent or empty label renders NO label row
childrenReactNode | (ctx) => ReactNodethe control
requiredbooleanrenders a decorative * (hidden from assistive tech)
errorstringrenders a role="alert" line, linked via the child's describedById
containerStyleViewStylemerged over the container
testIDstringon the container

The injected theme needs colors.{surface,text,textSecondary,border}, palette.primary['500'] and semantic.error['500'] — supplied via @dloizides/ui-feedback's provider. Without a provider the components fall back to a neutral default theme.

ChipSelector

<ChipSelector
  label="Plan"
  required
  error={errors.plan}
  options={plans}
  value={plan}
  onChange={setPlan}
  variant="outline"
/>

Its label, required mark, error line and bottom spacing come from Field. label is optional: with no label no label row is rendered, so it drops into a toolbar or filter bar cleanly.

PropTypeNotes
labelstringoptional — no label means no label row
optionsArray<{ value, label }>value is a string or number
valueT | T[]array when multiple
onChange(value: T) => voidfires the pressed value; the parent owns toggle logic
multiplebooleanselection is an array
disabledbooleandisables every chip
variant'solid' | 'outline'solid (default) = filled pill; outline = tinted outline
requiredbooleanrenders Field's decorative *
errorstringrole="alert" line, tied to the chip group via aria-describedby
containerStyleViewStylemerged over the container
testIDstringon the container

Dense controls — SelectControl / TypeaheadControl / DateRangeControl

Promoted in 1.8.0 out of @dloizides/ui-tables' private filter bar, where they worked correctly for six portals and were exported to none — which is why the fleet grew 6 selects, 5 date fields and 2 typeaheads.

They are label-free by design. Compose them inside Field so there is ONE label implementation for every control rather than one per control:

<Field label="Status" labelVariant="control" containerStyle={{ marginBottom: 0 }}>
  <SelectControl
    accessibilityLabel={t('filters.statusName', 'Status', selectedLabel)}
    options={options}
    testID="filters-status"
    value={value}
    onChange={setValue}
  />
</Field>

labelVariant="control" is the 11/700/uppercase voice from FORMS.md — the voice for labels that are SCANNED (filter bars, toolbars) rather than READ.

Every string is pre-localized

This package never calls t. In particular SelectControl's accessibilityLabel must be composed by YOU and must carry the selection — "Status: Active", not "Status". The accessible name REPLACES the trigger's visible text for a screen reader, so naming it with the field alone silently hides what is selected.

ControlKey propstestIDs
SelectControloptions, value, onChange, placeholder, accessibilityLabel, optionHint<testID>-trigger, -menu, -option-<value>
TypeaheadControloptions, value, onChange, onSubmit, error, minChars, maxSuggestions<testID>-input, -menu, -error
DateRangeControlvalue ({from,to}), onChange, onSubmit, fromLabel, toLabel<testID>-range, -from, -to
AnchoredMenuthe floating list the first two compose<testID>-menu

Also exported: controlStyles (the tuned metrics), suggestOptions / isUnmatched (the typeahead's ranker), and the ControlOption / DateRangeValue types.

testIDs

form-field-input, chip-selector-chip-<value>, form-switch (overridable on FormSwitch).

License

MIT

版本与发布记录

@dloizides/ui-forms 共发布 54 个版本,首次发布于 2026/06/16;过去 12 个月发布了 54 个版本。

版本发布日期距今
1.38.0latest2026/11/12今天
1.37.02026/11/12今天
1.36.02026/11/12今天
1.35.02026/11/12今天
1.34.12026/11/12今天
1.34.02026/11/12今天

关于 @dloizides/ui-forms 的常见问题

@dloizides/ui-forms 是什么?

Themable, brand-agnostic React Native (RN-web) form components — FormField, ChipSelector, FormSwitch — sharing the @dloizides/ui-feedback UI context. Part of the dloizides.com shared UI kit.

如何安装 @dloizides/ui-forms?

在项目目录运行 npm install @dloizides/ui-forms,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(>=18.0.0)、react-native(>=0.74.0)、react-native-svg(>=13.0.0)、@dloizides/ui-buttons(>=1.20.1)、@dloizides/ui-feedback(>=1.1.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@dloizides/ui-forms 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@dloizides/ui-forms 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@dloizides/ui-forms 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@dloizides/ui-forms 可以商用吗?

@dloizides/ui-forms 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@dloizides/ui-forms 的下载量有多少?

根据 npm 官方下载统计,@dloizides/ui-forms 在 2026/10/13 – 2026/11/11 这 30 天内被下载 5,794 次,日均约 193 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@dloizides/ui-forms 还在维护吗?

最新版本 1.38.0 发布于 2026/11/12(今天);至今共发布 54 个版本,其中过去 12 个月发布了 54 个;首次发布于 2026/06/16。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。