Skip to content

feat: add OTP field component#802

Open
rohanchkrabrty wants to merge 4 commits into
mainfrom
worktree-otp-field
Open

feat: add OTP field component#802
rohanchkrabrty wants to merge 4 commits into
mainfrom
worktree-otp-field

Conversation

@rohanchkrabrty
Copy link
Copy Markdown
Contributor

Summary

  • New OTPField component built on Base UI's OTP field with composable OTPField.Input and OTPField.Separator slots
  • Slot styling mirrors the Input component (border/background tokens, hover/focus/invalid states) to match Figma
  • Interactive playground in docs covering length, validationType, mask, disabled, readOnly, autoSubmit
  • Examples for separator, masked, alphanumeric, controlled, complete callback, custom sanitization, and Field wrapper
  • Unit tests covering value entry, masking, disabled/read-only behavior, keyboard navigation, and ref forwarding

@vercel
Copy link
Copy Markdown

vercel Bot commented May 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
apsara Ready Ready Preview, Comment May 14, 2026 4:20am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 30834531-8ab1-4554-8012-edd9e5ca9fcd

📥 Commits

Reviewing files that changed from the base of the PR and between 8f2dec5 and 46541c6.

📒 Files selected for processing (3)
  • apps/www/src/components/playground/otp-field-examples.tsx
  • apps/www/src/content/docs/components/otp-field/index.mdx
  • packages/raystack/components/slider/__tests__/slider.test.tsx
✅ Files skipped from review due to trivial changes (1)
  • apps/www/src/content/docs/components/otp-field/index.mdx
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/raystack/components/slider/tests/slider.test.tsx
  • apps/www/src/components/playground/otp-field-examples.tsx

📝 Walkthrough

Walkthrough

This pull request introduces a complete OTPField component to the Raystack UI library. The implementation wraps @base-ui/react OTP field primitives with a styled React component, includes type definitions documenting the public API, and is accompanied by comprehensive test coverage, interactive playground examples, and detailed documentation with multiple code examples demonstrating all supported features and behaviors.

Suggested reviewers

  • rsbh
  • paanSinghCoder
  • Shreyag02
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add OTP field component' clearly and concisely describes the main change in the changeset—adding a new OTPField component to the codebase.
Description check ✅ Passed The description is directly related to the changeset, providing a detailed summary of the new OTPField component, its features, examples, and testing coverage.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/www/src/content/docs/components/otp-field/index.mdx (1)

25-25: 💤 Low value

Consider clarifying the length requirement explanation.

The phrase "before all slots hydrate" is slightly confusing. The length prop is required so the component can:

  • Size the input correctly
  • Validate the complete value
  • Detect when all slots are filled

Consider rewording to: "length is required so the field can manage state, validate input, and detect completion."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/www/src/content/docs/components/otp-field/index.mdx` at line 25, Update
the explanatory sentence about the length prop in the OTP field docs: replace
the confusing phrase that mentions "before all slots hydrate" with a clearer
description that references the length prop's responsibilities (e.g., "`length`
is required so the field can manage state, validate input, and detect
completion"). Locate the text in
apps/www/src/content/docs/components/otp-field/index.mdx where the `length` prop
is explained and swap the sentence while keeping the surrounding import/assembly
guidance intact and still mentioning sizing, validation, and completion
detection for the `length` prop.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/www/src/components/playground/otp-field-examples.tsx`:
- Around line 7-13: renderSlots currently computes aria-label totals using
length + offset, which produces incorrect "of" counts for grouped/separated
examples; change the function signature to accept a separate totalLength (e.g.,
renderSlots(length: number, offset = 0, totalLength = length)) and use
totalLength in the aria-label for OTPField.Input (use `Character ${i + 1 +
offset} of ${totalLength}`). Update all calls to renderSlots (including the
separator example and the other instance around lines 58-66) to pass the full
field length as the third argument so screen readers see the correct total.

---

Nitpick comments:
In `@apps/www/src/content/docs/components/otp-field/index.mdx`:
- Line 25: Update the explanatory sentence about the length prop in the OTP
field docs: replace the confusing phrase that mentions "before all slots
hydrate" with a clearer description that references the length prop's
responsibilities (e.g., "`length` is required so the field can manage state,
validate input, and detect completion"). Locate the text in
apps/www/src/content/docs/components/otp-field/index.mdx where the `length` prop
is explained and swap the sentence while keeping the surrounding import/assembly
guidance intact and still mentioning sizing, validation, and completion
detection for the `length` prop.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 90a47a3a-70de-49f4-81d4-bbf6a32a4950

📥 Commits

Reviewing files that changed from the base of the PR and between 055019e and 7b44095.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • apps/www/src/components/playground/index.ts
  • apps/www/src/components/playground/otp-field-examples.tsx
  • apps/www/src/content/docs/components/otp-field/demo.ts
  • apps/www/src/content/docs/components/otp-field/index.mdx
  • apps/www/src/content/docs/components/otp-field/props.ts
  • packages/raystack/components/otp-field/__tests__/otp-field.test.tsx
  • packages/raystack/components/otp-field/index.tsx
  • packages/raystack/components/otp-field/otp-field.module.css
  • packages/raystack/components/otp-field/otp-field.tsx
  • packages/raystack/index.tsx
  • packages/raystack/package.json

Comment thread apps/www/src/components/playground/otp-field-examples.tsx Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/raystack/components/slider/__tests__/slider.test.tsx`:
- Around line 140-146: The test "sets aria-valuetext" currently only checks
existence of the input but not the attribute; update the assertion for the
Slider render (the test using render(<Slider value={50} aria-valuetext='50
percent' />), container.querySelector('input[type="range"]') and the slider
variable) to assert that the input has aria-valuetext equal to '50 percent'
(e.g., use expect(slider).toHaveAttribute('aria-valuetext', '50 percent') or
equivalent).
- Around line 79-83: The tests for Slider are inconsistent: "handles single
value" uses synchronous assertions but "handles range values" uses waitFor
unnecessarily; since both are controlled props their attributes should be set on
initial render, so remove the async waitFor from the "handles range values" test
and use the same synchronous pattern as in "handles single value" (query the
input[type=\"range\"] and assert aria-valuenow, aria-valuemin and aria-valuemax
directly). Locate the tests by their descriptions ("handles single value" and
"handles range values") in slider.test.tsx and update the latter to match the
synchronous assertions used in the former.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d82d8cc1-6039-4595-8587-7c0804e306f2

📥 Commits

Reviewing files that changed from the base of the PR and between 7b44095 and 8f2dec5.

📒 Files selected for processing (2)
  • packages/raystack/components/slider/__tests__/slider.test.tsx
  • packages/raystack/index.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/raystack/index.tsx

Comment thread packages/raystack/components/slider/__tests__/slider.test.tsx
Comment thread packages/raystack/components/slider/__tests__/slider.test.tsx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant