rc-time-picker
A lightweight, controllable React time picker component with hour, minute, and second selection panels.
Repository Health
Technical Analysis
rc-time-picker is a React component from the react-component ecosystem (the same group behind rc-trigger, rc-select, and others used inside Ant Design) that provides a text input paired with a dropdown time-selection panel. The panel splits into scrollable Header and Combobox sub-columns for hours, minutes, and seconds, each independently togglable and steppable, with support for 12-hour AM/PM mode, per-column disabled-value predicates, and custom clear/input icons.
It is built on moment.js for value parsing/formatting and rc-trigger for popup positioning, and ships both controlled (value/onChange) and uncontrolled (defaultValue) usage patterns. Ant Design’s own TimePicker wraps this package internally, making it a common dependency to encounter indirectly even in codebases that never import it by name.
What You Get
- A
<TimePicker>component with an input field, dropdown panel, and optional clear button - Bundled TypeScript type definitions (index.d.ts) for props and the exported component
- A
Panelsub-component exposing aclose()method for building custom addons (e.g. an OK button) - Example pages covering disabled ranges, custom formats, 12-hour mode, and step increments
- CJS (
lib/) and ESM (es/) build outputs plus a separate compiled CSS/Less theme
Common Use Cases
- Adding a time-only input to a booking, reservation, or check-in form
- Restricting selectable hours/minutes to business hours or existing availability windows
- Building a lightweight scheduling widget without adopting a full date+time library
- Wrapping the component inside a larger design system, the way Ant Design’s TimePicker does
Under The Hood
Architecture
The component tree is a shallow three-layer stack: TimePicker (in src/TimePicker.jsx) composes rc-trigger for popup positioning and lazily renders a Panel via getPanelElement(); Panel (src/Panel.jsx) computes hour/minute/second option arrays through a local generateOptions helper that applies disabled-value filters and step intervals, then hands them down to Header (the text-entry strip) and Combobox (the scrollable select columns). State flows entirely through props and callbacks plus getDerivedStateFromProps for controlled value/open props — there is no external store. Because Header and Combobox both depend on the same disabled-option/format contract computed in Panel, changing that contract ripples into both siblings, a tightly-coupled but easy-to-trace pattern typical of pre-hooks class components.
Tech Stack
React 16 class components (peerDependencies pin ^16.0.0 for react/react-dom), moment 2.x for time parsing/formatting, rc-trigger ^4.0.0-alpha.8 for popup placement (configured via src/placements.js), classnames for conditional class composition, and raf for animation-frame scheduling. The library is built with father (Umi’s library bundler) producing both lib/ (CommonJS) and es/ (ESM) outputs, with a separate lessc step compiling assets/index.less to distributable CSS. Linting runs through @umijs/fabric’s shared ESLint config, and CircleCI runs lint and test --coverage jobs on every push.
Code Quality
Tests live in tests/ (TimePicker.spec.jsx, Header.spec.jsx, Select.spec.jsx) using Enzyme’s mount, backed by a shared tests/util.js helper (clickInput, clickSelectItem, matchValue) and one snapshot file; npm test runs father test with coverage support. Error handling is minimal by design — the codebase is presentation logic with almost no I/O, and unset callback props default to no-ops rather than throwing. Naming is consistent camelCase mirroring sibling rc-* packages’ controlled/uncontrolled prop conventions. There is no static typing on the source itself (plain JSX, not TSX) beyond the hand-maintained .d.ts file, and ESLint is enforced in CI.
API Design
The public surface is a single default-exported component with a flat, thoroughly documented prop table covering granularity toggles, disabled-value predicates, step increments, and 12-hour mode — getting started requires only importing the component and its stylesheet. Escape hatches like addon (render a footer with access to the live panel instance) and getPopupContainer give it enough extensibility to serve as the base for Ant Design’s richer TimePicker without forking. The main friction points are a hard dependency on moment (now a legacy choice in the ecosystem) for the value/onChange type, and separate disabledHours/disabledMinutes/disabledSeconds callback props rather than one unified predicate — slightly more boilerplate than an equivalent hook-based API would require.