Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { OTPFieldPreview as OTPField } from '@base-ui/react/otp-field';
import { OTPField } from '@base-ui/react/otp-field';
import styles from './index.module.css';

const CODE_LENGTH = 6;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { OTPFieldPreview as OTPField } from '@base-ui/react/otp-field';
import { OTPField } from '@base-ui/react/otp-field';

const CODE_LENGTH = 6;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';
import * as React from 'react';
import { OTPFieldPreview as OTPField } from '@base-ui/react/otp-field';
import { OTPField } from '@base-ui/react/otp-field';
import { useInvalidFeedback } from '../useInvalidFeedback';
import styles from './index.module.css';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { OTPFieldPreview as OTPField } from '@base-ui/react/otp-field';
import { OTPField } from '@base-ui/react/otp-field';
import styles from './index.module.css';

const CODE_LENGTH = 6;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { OTPFieldPreview as OTPField } from '@base-ui/react/otp-field';
import { OTPField } from '@base-ui/react/otp-field';

const CODE_LENGTH = 6;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { OTPFieldPreview as OTPField } from '@base-ui/react/otp-field';
import { OTPField } from '@base-ui/react/otp-field';
import styles from './index.module.css';

const OTP_LENGTH = 6;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { OTPFieldPreview as OTPField } from '@base-ui/react/otp-field';
import { OTPField } from '@base-ui/react/otp-field';

const OTP_LENGTH = 6;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { OTPFieldPreview as OTPField } from '@base-ui/react/otp-field';
import { OTPField } from '@base-ui/react/otp-field';
import styles from './index.module.css';

const OTP_LENGTH = 6;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { OTPFieldPreview as OTPField } from '@base-ui/react/otp-field';
import { OTPField } from '@base-ui/react/otp-field';

const OTP_LENGTH = 6;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { OTPFieldPreview as OTPField } from '@base-ui/react/otp-field';
import { OTPField } from '@base-ui/react/otp-field';
import styles from './index.module.css';

const CODE_LENGTH = 6;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { OTPFieldPreview as OTPField } from '@base-ui/react/otp-field';
import { OTPField } from '@base-ui/react/otp-field';

const CODE_LENGTH = 6;

Expand Down
21 changes: 18 additions & 3 deletions docs/src/app/(docs)/react/components/otp-field/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
content="A high-quality, unstyled React OTP field component for one-time password and verification code entry."
/>

> **Note:** OTP Field is currently in preview. Its API may change before it becomes stable.

import { DemoOTPFieldHero } from './demos/hero';

<DemoOTPFieldHero />
Expand All @@ -22,7 +20,7 @@ import { DemoOTPFieldHero } from './demos/hero';
Import the component and assemble its parts:

```jsx title="Anatomy"
import { OTPFieldPreview as OTPField } from '@base-ui/react/otp-field';
import { OTPField } from '@base-ui/react/otp-field';

<OTPField.Root>
<OTPField.Input />
Expand Down Expand Up @@ -127,6 +125,23 @@ import { DemoOTPFieldPassword } from './demos/password';

<DemoOTPFieldPassword compact />

### Autofill and password managers

The browser's native one-time-code suggestions and password manager autofill both target the first
slot, which holds a `maxLength` matching the OTP `length` so a complete code can be filled and
distributed across the remaining slots.

Some password managers position their inline autofill popup relative to the focused input and skip
narrow inputs. For example, 1Password's inline popup does not appear for inputs narrower than `80px`
(filling from the browser extension still works). If you need the inline popup, give the first slot
enough width, or render a wider visually-styled first slot:

```css title="Give the first slot enough width for the inline popup"
.Input:first-child {
min-width: 80px;
}
```

## API reference

import { TypesOTPField } from './types';
Expand Down
331 changes: 51 additions & 280 deletions docs/src/app/(docs)/react/components/otp-field/types.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/src/app/(docs)/react/components/otp-field/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { OTPFieldPreview } from '@base-ui/react/otp-field';
import { OTPField } from '@base-ui/react/otp-field';
import { createMultipleTypes } from 'docs/src/utils/createTypes';

const { types, AdditionalTypes } = createMultipleTypes(import.meta.url, OTPFieldPreview);
const { types, AdditionalTypes } = createMultipleTypes(import.meta.url, OTPField);

export const TypesOTPField = types;
export const TypesOTPFieldAdditional = AdditionalTypes;
5 changes: 3 additions & 2 deletions docs/src/app/(docs)/react/components/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
- Meter - ([Outline](#meter), [Contents](./meter/page.mdx))
- Navigation Menu - ([Outline](#navigation-menu), [Contents](./navigation-menu/page.mdx))
- Number Field - ([Outline](#number-field), [Contents](./number-field/page.mdx))
- OTP Field [Preview] - ([Outline](#otp-field), [Contents](./otp-field/page.mdx))
- OTP Field [New] - ([Outline](#otp-field), [Contents](./otp-field/page.mdx))
- Popover - ([Outline](#popover), [Contents](./popover/page.mdx))
- Preview Card - ([Outline](#preview-card), [Contents](./preview-card/page.mdx))
- Progress - ([Outline](#progress), [Contents](./progress/page.mdx))
Expand Down Expand Up @@ -1205,6 +1205,7 @@ A one-time password input composed of individual character slots.
- Placeholder hints
- Custom normalization
- Masked entry
- Autofill and password managers
- API reference
- Root
- Input
Expand All @@ -1218,7 +1219,7 @@ A one-time password input composed of individual character slots.
- Data Attributes: data-complete, data-dirty, data-disabled, data-filled, data-focused, data-invalid, data-readonly, data-required, data-touched, data-valid
- OTP Field - Separator
- Props: className, orientation, render, style
- Types: OTPFieldPreview.Input.Props, OTPFieldPreview.Input.State, OTPFieldPreview.Root.ChangeEventDetails, OTPFieldPreview.Root.ChangeEventReason, OTPFieldPreview.Root.CompleteEventDetails, OTPFieldPreview.Root.CompleteEventReason, OTPFieldPreview.Root.InvalidEventDetails, OTPFieldPreview.Root.InvalidEventReason, OTPFieldPreview.Root.Props, OTPFieldPreview.Root.State, OTPFieldPreview.Root.ValidationType, OTPFieldPreview.Separator.Props, OTPFieldPreview.Separator.State
- Types: OTPField.Input.Props, OTPField.Input.State, OTPField.Root.ChangeEventDetails, OTPField.Root.ChangeEventReason, OTPField.Root.CompleteEventDetails, OTPField.Root.CompleteEventReason, OTPField.Root.InvalidEventDetails, OTPField.Root.InvalidEventReason, OTPField.Root.Props, OTPField.Root.State, OTPField.Root.ValidationType, OTPField.Separator.Props, OTPField.Separator.State

</details>

Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/otp-field/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * as OTPFieldPreview from './index.parts';
export * as OTPField from './index.parts';

export type * from './root/OTPFieldRoot';
export type * from './input/OTPFieldInput';
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OTPFieldPreview as OTPField } from '@base-ui/react/otp-field';
import { OTPField } from '@base-ui/react/otp-field';

// @ts-expect-error - slot order is inferred from render order
const noExplicitIndexSupport = <OTPField.Input index={0} />;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { expect, vi } from 'vitest';
import * as React from 'react';
import userEvent from '@testing-library/user-event';
import { act, fireEvent, screen } from '@mui/internal-test-utils';
import { OTPFieldPreview as OTPField } from '@base-ui/react/otp-field';
import { OTPField } from '@base-ui/react/otp-field';
import { Field } from '@base-ui/react/field';
import { DirectionProvider } from '@base-ui/react/direction-provider';
import { createRenderer, describeConformance, isJSDOM } from '#test-utils';
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/otp-field/root/OTPFieldRoot.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expectType } from '#test-utils';
import { OTPFieldPreview as OTPField } from '@base-ui/react/otp-field';
import { OTPField } from '@base-ui/react/otp-field';
import { REASONS } from '../../internals/reasons';

type OTPFieldChangeHandler = NonNullable<OTPField.Root.Props['onValueChange']>;
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/otp-field/root/OTPFieldRoot.test.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { expect, vi } from 'vitest';
import * as React from 'react';
import { act, fireEvent, screen } from '@mui/internal-test-utils';
import { OTPFieldPreview as OTPFieldBase } from '@base-ui/react/otp-field';
import { OTPField as OTPFieldBase } from '@base-ui/react/otp-field';
import { Field } from '@base-ui/react/field';
import { Form } from '@base-ui/react/form';
import { createRenderer, describeConformance, isJSDOM } from '#test-utils';
import { REASONS } from '../../internals/reasons';

describe('<OTPFieldPreview />', () => {
describe('<OTPField.Root />', () => {
const { render, renderToString } = createRenderer();
const OTP_LENGTH = 6;

Expand Down
Loading