Edit Component
Adding OTP RS to your project is simple:
-
Make sure your project is set up with Yew. Follow their Getting Started Guide for setup instructions.
-
Add the OTP RS component to your dependencies by including it in your Cargo.toml file:
cargo add otprs --features=yew
-
Import the Otp, Group, Separator, and Slot components into your Yew component and start using them in your app.
use otprs::yew::{Otp, Group, Separator, Slot};
use yew::prelude::*;
#[function_component(BasicOtp)]
pub fn basic_otp() -> Html {
html! {
<Otp max_length={6} aria_label="Enter verification code">
<Group>
<Slot index={0} />
<Slot index={1} />
<Slot index={2} />
</Group>
<Separator />
<Group>
<Slot index={3} />
<Slot index={4} />
<Slot index={5} />
</Group>
</Otp>
}
}
use otprs::yew::{Otp, Group, Separator, Slot};
use yew::prelude::*;
#[function_component(ControlledOtp)]
pub fn controlled_otp() -> Html {
let value = use_state(String::new);
let on_change = {
let value = value.clone();
Callback::from(move |v: String| value.set(v))
};
let on_complete = Callback::from(|code: String| {
web_sys::console::log_1(&format!("Complete: {code}").into());
});
html! {
<Otp
max_length={6}
value={(*value).clone()}
on_change={on_change}
on_complete={on_complete}
aria_label="Verification code"
>
<Group>
<Slot index={0} />
<Slot index={1} />
<Slot index={2} />
</Group>
<Separator />
<Group>
<Slot index={3} />
<Slot index={4} />
<Slot index={5} />
</Group>
</Otp>
}
}
use otprs::yew::{Otp, Group, Slot};
use yew::prelude::*;
#[function_component(DisabledOtp)]
pub fn disabled_otp() -> Html {
html! {
<Otp max_length={4} is_disabled={true} aria_label="Disabled PIN">
<Group>
<Slot index={0} />
<Slot index={1} />
<Slot index={2} />
<Slot index={3} />
</Group>
</Otp>
}
}
use otprs::yew::{Otp, Group, Separator, Slot};
use otprs::Variant;
use yew::prelude::*;
#[function_component(SecondaryOtp)]
pub fn secondary_otp() -> Html {
html! {
<Otp max_length={6} variant={Variant::Secondary} aria_label="Enter code">
<Group>
<Slot index={0} />
<Slot index={1} />
<Slot index={2} />
</Group>
<Separator />
<Group>
<Slot index={3} />
<Slot index={4} />
<Slot index={5} />
</Group>
</Otp>
}
}
| Property | Type | Description | Default |
max_length | usize | Total slot count. | 6 |
value | String | Controlled value. | "" |
on_change | Callback<String> | Called on every keystroke. | no-op |
on_complete | Callback<String> | Called when all slots filled. | no-op |
is_disabled | bool | Disables all slots. | false |
is_invalid | bool | Shows error state on all slots. | false |
variant | Variant | Primary or Secondary. | Primary |
pattern | &'static str | Allowed character regex. | "[0-9]" |
input_mode | InputMode | Mobile keyboard type. | Numeric |
name | &'static str | Hidden input name for forms. | "" |
auto_focus | bool | Focus first slot on mount. | false |
class | &'static str | Extra CSS class on root. | "" |
style | &'static str | Extra inline CSS on root. | "" |
id | &'static str | id on root element. | "" |
aria_label | &'static str | Screen-reader label. | "One-time password" |
aria_describedby | &'static str | Error description element id. | "" |
container_class | &'static str | Vlass on inner container. | "" |
container_style | &'static str | Inline CSS on inner container. | "" |
| Property | Type | Description | Default |
index | usize | Zero-based slot index. Required. | - |
class | &'static str | Extra CSS on slot wrapper. | "" |
style | &'static str | Extra inline CSS on slot. | "" |
id | &'static str | id on slot wrapper. | "" |
| Property | Type | Description | Default |
class | &'static str | Extra CSS on group. | "" |
style | &'static str | Inline CSS on group. | "" |
id | &'static str | id on group element. | "" |
| Property | Type | Description | Default |
class | &'static str | Extra CSS on separator. | "" |
style | &'static str | Inline CSS on separator. | "" |
Slot must be a descendant of Otp, it reads context from the parent.
- The caret blinks inside the active empty slot for a native feel.
- Use
pattern={otprs::pattern::CHARS_ONLY} for letter-only codes.
- Use
is_invalid={true} together with aria_describedby to surface errors accessibly.
- Input RS: The unstyled
<input> abstraction layer powering the invisible focus engine.
- RFC 4226: HOTP: An HMAC-Based One-Time Password Algorithm.
- RFC 6238: TOTP: Time-Based One-Time Password Algorithm.
- totp-rs: The underlying Rust crate used by
otprs for TOTP validation.
You can import OTP RS directly into your project to customize and modify it using the opensass cli:
os add otprs yew
Edit Component
Adding OTP RS to your project is simple:
-
Make sure your project is set up with Dioxus. Follow their Getting Started Guide for setup instructions.
-
Add the OTP RS component to your dependencies by including it in your Cargo.toml file:
cargo add otprs --features=dio
-
Import the Otp, Group, Separator, and Slot components into your Dioxus component and start using them in your app.
use otprs::dioxus::{Otp, Group, Separator, Slot};
use dioxus::prelude::*;
#[component]
fn BasicOtp() -> Element {
rsx! {
Otp { max_length: 6, aria_label: "Enter verification code",
Group {
Slot { index: 0 }
Slot { index: 1 }
Slot { index: 2 }
}
Separator {}
Group {
Slot { index: 3 }
Slot { index: 4 }
Slot { index: 5 }
}
}
}
}
use otprs::dioxus::{Otp, Group, Separator, Slot};
use dioxus::prelude::*;
#[component]
fn ControlledOtp() -> Element {
let mut value = use_signal(String::new);
rsx! {
Otp {
max_length: 6,
value: value(),
on_change: Some(Callback::new(move |v: String| value.set(v))),
on_complete: Some(Callback::new(|code: String| {
dioxus_logger::tracing::info!("Complete: {code}");
})),
aria_label: "Verification code",
Group {
Slot { index: 0 }
Slot { index: 1 }
Slot { index: 2 }
}
Separator {}
Group {
Slot { index: 3 }
Slot { index: 4 }
Slot { index: 5 }
}
}
}
}
use otprs::dioxus::{Otp, Group, Slot};
use dioxus::prelude::*;
#[component]
fn PinOtp() -> Element {
rsx! {
Otp { max_length: 4, aria_label: "Enter PIN",
Group {
Slot { index: 0 }
Slot { index: 1 }
Slot { index: 2 }
Slot { index: 3 }
}
}
}
}
| Property | Type | Description | Default |
max_length | usize | Total slot count. | 6 |
value | String | Controlled value. | "" |
on_change | Option<Callback<String>> | Called on every keystroke. | None |
on_complete | Option<Callback<String>> | Called when all slots filled. | None |
is_disabled | bool | Disables all slots. | false |
is_invalid | bool | Shows error state. | false |
variant | Variant | Primary or Secondary. | Primary |
pattern | &'static str | Allowed character regex. | "[0-9]" |
input_mode | InputMode | Mobile keyboard type. | Numeric |
name | &'static str | Hidden input name. | "" |
auto_focus | bool | Focus first slot on mount. | false |
class | &'static str | Extra CSS class on root. | "" |
style | &'static str | Inline CSS on root. | "" |
id | &'static str | id on root element. | "" |
aria_label | &'static str | Screen-reader label. | "One-time password" |
container_class | &'static str | Class on inner container. | "" |
container_style | &'static str | CSS on inner container. | "" |
| Property | Type | Description | Default |
index | usize | Zero-based slot index. Required. | - |
class | &'static str | Extra CSS on slot. | "" |
style | &'static str | Inline CSS on slot. | "" |
id | &'static str | id on slot. | "" |
| Property | Type | Description | Default |
class | &'static str | Extra CSS. | "" |
style | &'static str | Inline CSS. | "" |
id | &'static str | id attribute. | "" |
Slot must be inside an Otp, it reads context from the parent.
- Focus traversal: Typing a character auto-advances to the next slot; pressing
Backspace clears the current slot and retreats focus to the previous one. Focus stops at the last slot when the OTP is full.
- Multiple instances: Each
Otp on the page gets a unique internal ID, so placing several Otp widgets on the same page is fully supported without conflict.
- Use
is_invalid: true together with aria_describedby to surface errors accessibly.
- Use
pattern: "[A-Za-z0-9]" for alphanumeric codes instead of the default "[0-9]".
- Input RS: The unstyled
<input> abstraction layer powering the invisible focus engine.
- RFC 4226: HOTP: An HMAC-Based One-Time Password Algorithm.
- RFC 6238: TOTP: Time-Based One-Time Password Algorithm.
- totp-rs: The underlying Rust crate used by
otprs for TOTP validation.
You can import OTP RS directly into your project to customize and modify it using the opensass cli:
os add otprs dio
Edit Component
Adding OTP RS to your project is simple:
-
Make sure your project is set up with Leptos. Follow their Getting Started Guide for setup instructions.
-
Add the OTP RS component to your dependencies by including it in your Cargo.toml file:
cargo add otprs --features=lep
-
Import the Otp, Group, Separator, and Slot components into your Leptos component and start using them in your app.
use otprs::leptos::{Otp, Group, Separator, Slot};
use leptos::prelude::*;
#[component]
pub fn BasicOtp() -> impl IntoView {
view! {
<Otp max_length=6 aria_label="Enter verification code">
<Group>
<Slot index=0 />
<Slot index=1 />
<Slot index=2 />
</Group>
<Separator />
<Group>
<Slot index=3 />
<Slot index=4 />
<Slot index=5 />
</Group>
</Otp>
}
}
use otprs::leptos::{Otp, Group, Separator, Slot};
use leptos::prelude::*;
#[component]
pub fn ControlledOtp() -> impl IntoView {
let (value, set_value) = signal(String::new());
let on_change = Callback::new(move |v: String| set_value.set(v));
let on_complete = Callback::new(move |code: String| {
leptos::logging::log!("Complete: {code}");
});
view! {
<Otp
max_length=6
value=value.get()
on_change=on_change
on_complete=on_complete
aria_label="Enter your code"
>
<Group>
<Slot index=0 />
<Slot index=1 />
<Slot index=2 />
</Group>
<Separator />
<Group>
<Slot index=3 />
<Slot index=4 />
<Slot index=5 />
</Group>
</Otp>
}
}
use otprs::leptos::{Otp, Group, Slot};
use leptos::prelude::*;
#[component]
pub fn InvalidOtp() -> impl IntoView {
view! {
<div>
<Otp
max_length=6
is_invalid=true
aria_label="Invalid verification code"
aria_describedby="otp-error"
>
<Group>
<Slot index=0 />
<Slot index=1 />
<Slot index=2 />
<Slot index=3 />
<Slot index=4 />
<Slot index=5 />
</Group>
</Otp>
<p id="otp-error" role="alert" style="color: #dc2626; margin-top: 4px;">
"Incorrect code. Please try again."
</p>
</div>
}
}
| Property | Type | Description | Default |
max_length | usize | Total slot count. | 6 |
value | String | Controlled value. | "" |
on_change | Option<Callback<String>> | Called on every change. | None |
on_complete | Option<Callback<String>> | Called when all slots filled. | None |
is_disabled | bool | Disables all slots. | false |
is_invalid | bool | Shows error state. | false |
variant | Variant | Primary or Secondary. | Primary |
pattern | &'static str | Allowed character regex. | "[0-9]" |
input_mode | InputMode | Mobile keyboard type. | Numeric |
name | &'static str | Hidden input name. | "" |
auto_focus | bool | Focus first slot on mount. | false |
class | &'static str | Extra CSS class on root. | "" |
style | &'static str | Inline CSS on root. | "" |
id | &'static str | id on root element. | "" |
aria_label | &'static str | Screen-reader label. | "One-time password" |
aria_describedby | &'static str | Error description element id. | "" |
container_class | &'static str | Class on inner container. | "" |
container_style | &'static str | CSS on inner container. | "" |
| Property | Type | Description | Default |
index | usize | Zero-based slot index. Required. | - |
class | &'static str | Extra CSS on slot. | "" |
style | &'static str | Inline CSS on slot. | "" |
id | &'static str | id on slot. | "" |
| Property | Type | Description | Default |
class | &'static str | Extra CSS. | "" |
style | &'static str | Inline CSS. | "" |
id | &'static str | id attribute. | "" |
Slot must be inside an Otp, it reads context via Leptos use_context.
- Focus traversal: After typing a character the focus automatically moves to the next slot. Pressing
Backspace clears the current slot and retreats focus to the previous one. Focus stops at the last slot when the OTP is full.
- Multiple instances: Each
Otp on the page gets a unique internal ID, so placing several Otp widgets on the same page is fully supported without any conflict.
- Use
is_invalid=true with aria_describedby to link error messages accessibly.
- Use
pattern="[A-Za-z0-9]" for alphanumeric codes instead of the default "[0-9]".
- The blinking caret in the active empty slot is pure CSS, no JS timers.
- Input RS: The unstyled
<input> abstraction layer powering the invisible focus engine.
- RFC 4226: HOTP: An HMAC-Based One-Time Password Algorithm.
- RFC 6238: TOTP: Time-Based One-Time Password Algorithm.
- totp-rs: The underlying Rust crate used by
otprs for TOTP validation.
You can import OTP RS directly into your project to customize and modify it using the opensass cli:
os add otprs lep