@siamf/otp-timer
Version:
A simple react otp timer component with resend functionality🤷
220 lines (188 loc) • 8.02 kB
Markdown
<br/>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/siamahnaf/assets-kit/main/logo/logo-white.png">
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/siamahnaf/assets-kit/main/logo/logo-black.png">
<img alt="Siam Ahnaf" src="https://raw.githubusercontent.com/siamahnaf/assets-kit/main/logo/logo-black.png" height="auto" width="240">
</picture>
<br/> <br/>
# @siamf/otp-timer
A simple and customizable react otp timer & input component with typescript support. very simple and more customizable design and smallest bundle size. You can use this component into any react and nextjs projects.
<a href="https://www.buymeacoffee.com/siamahnaf" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
- SSR Friendly
- Customizable
- TypeScript Support
- Smallest Bundle Size(About 13kb)
- Otp Timer & Otp Input Component
## Installation
```shell-script
$ npm i @siamf/otp-timer
```
## Demo
<img src="https://res.cloudinary.com/dub0dpenl/image/upload/v1672334376/otp-timer-ts_f8ebe8.gif" alt="Girl in a jacket" width="250">
## Usage?
### `OtpTimer` Component
```javascript
import { OtpTimer } from "@siamf/otp-timer";
const MyComponent = () => {
const handleResend = () => {
//desired function to be performed on clicking resend button
}
return (
<div>
<OtpTimer
minutes={0}
seconds={30}
onResend={handleResend}
renderText={(props) => <p>You can resend code in {props.minutes} minutes and {props.seconds} seconds</p>}
renderButton={(props) => <button {...props}>
Send Code Again
</button>}
/>
</div>
);
};
export default MyComponent;
```
### `OtpInput` Component
```javascript
import { useState } from "react";
import { OtpInput } from "@siamf/otp-timer";
export default function App() {
const [otp, setOtp] = useState<string>(");
return (
<OtpInput
value={otp}
onChange={setOtp}
numInputs={4}
renderSeparator={<span>-</span>}
renderInput={(props) => <input {...props} />}
/>
);
}
```
# Customization
## `OtpTimer` component
### Options
|name|Description|Default Value|
|:---:| :-------------:|:-----------:|
|seconds|number of seconds for which timer must be set|30|
|minutes|number of minutes for which the timer must be set|0|
|onResend|function that would get triggered on clicking the resend button|n/a|
|renderText|Customizable text content(See Example Code)|Required|
|renderButton|Customizable button content(See Example Code)|Required|
## `OtpInput` component
<table>
<tr>
<th>Name<br/></th>
<th>Type</th>
<th>Required</th>
<th>Default</th>
<th>Description</th>
</tr>
<tr>
<td>numInputs</td>
<td>number</td>
<td>true</td>
<td>4</td>
<td>Number of OTP inputs to be rendered.</td>
</tr>
<tr>
<td>renderInput</td>
<td>function</td>
<td>true</td>
<td>none</td>
<td>A function that returns the input that is supposed to be rendered for each of the input fields.
The function will get two arguments: <code>inputProps</code> and <code>index</code>. <code>inputProps</code> is an object that contains all the props <b>that should be passed to the input being rendered</b> (Overriding these props is not recommended because it might lead to some unexpected behaviour). <code>index</code> is the index of the input being rendered.
</td>
</tr>
<tr>
<td>onChange</td>
<td>function</td>
<td>true</td>
<td>console.log</td>
<td>Returns OTP code typed in inputs.</td>
</tr>
<tr>
<td>onPaste</td>
<td>function</td>
<td>false</td>
<td>none</td>
<td>Provide a custom onPaste event handler scoped to the OTP inputs container. Executes when content is pasted into any OTP field.
</br></br>
Example:
<pre>
const handlePaste: React.ClipboardEventHandler<HTMLDivElement> = (event) => {
const data = event.clipboardData.getData('text');
console.log(data)
};</pre>
</td>
</tr>
<tr>
<td>value</td>
<td>string / number</td>
<td>true</td>
<td>''</td>
<td>The value of the OTP passed into the component.</td>
</tr>
<tr>
<td>placeholder</td>
<td>string</td>
<td>false</td>
<td>none</td>
<td>Specify an expected value of each input. The length of this string should be equal to <code>numInputs</code>.</td>
</tr>
<tr>
<td>renderSeparator</td>
<td>component / function<br/></td>
<td>false</td>
<td>none</td>
<td>Provide a custom separator between inputs by passing a component. For instance, <code><span>-</span></code> would add <code>-</code> between each input.</td> You can also pass a function that returns a component, where the function will get the index of the separator being rendered as an argument.
</tr>
<tr>
<td>containerStyle</td>
<td>style (object) / className (string)</td>
<td>false</td>
<td>none</td>
<td>Style applied or class passed to container of inputs.</td>
</tr>
<tr>
<td>inputStyle</td>
<td>style (object) / className (string)</td>
<td>false</td>
<td>none</td>
<td>Style applied or class passed to each input.</td>
</tr>
<tr>
<td>inputType</td>
<td><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input#input_types"><input> type<a></td>
<td>false</td>
<td>text</td>
<td>The type of the input that will be passed to the input element being rendered. In v2 <code>isInputNum</code> used to set the input type as <code>tel</code> and prevented non numerical entries, so as to avoid the spin buttons added to the inputs with input type <code>number</code>. That behaviour is still supported if you pass <code>tel</code> to the inputType prop.</td>
</tr>
<tr>
<td>shouldAutoFocus</td>
<td>boolean</td>
<td>false</td>
<td>false</td>
<td>Auto focuses input on initial page load.</td>
</tr>
<tr>
<td>skipDefaultStyles</td>
<td>boolean</td>
<td>false</td>
<td>false</td>
<td>The component comes with default styles for legacy reasons. Pass <code>true</code> to skip those styles. This prop will be removed in the next major release.</td>
</tr>
</table>
## Issues
You are welcome to create an issue.
## Connect with me
<div style="display: flex; align-items: center; gap: 3px;">
<a href="https://wa.me/8801611994403"><img src="https://raw.githubusercontent.com/siamahnaf/assets-kit/main/icons/whatsapp.png" width="40" height="40"></a>
<a href="https://siamahnaf.com/" style="margin-right: 8px"><img src="https://raw.githubusercontent.com/siamahnaf/assets-kit/main/icons/web.png" width="40" height="40"></a>
<a href="https://www.linkedin.com/in/siamahnaf/" style="margin-right: 8px"><img src="https://raw.githubusercontent.com/siamahnaf/assets-kit/main/icons/linkedin.png" width="40" height="40"></a>
<a href="https://x.com/siamahnaf198" style="margin-right: 8px"><img src="https://raw.githubusercontent.com/siamahnaf/assets-kit/main/icons/x.png" width="40" height="40"></a>
<a href="https://www.facebook.com/siamahnaf198/" style="margin-right: 8px"><img src="https://raw.githubusercontent.com/siamahnaf/assets-kit/main/icons/facebook.png" width="40" height="40"></a>
<a href="https://t.me/siamahnaf198" style="margin-right: 8px"><img src="https://raw.githubusercontent.com/siamahnaf/assets-kit/main/icons/telegram.png" width="40" height="40"></a>
<a href="https://www.npmjs.com/~siamahnaf" style="margin-right: 8px"><img src="https://raw.githubusercontent.com/siamahnaf/assets-kit/main/icons/npm.png" width="40" height="40"></a>
</div>