Phone field
An international phone number: searchable country picker, grouping as you type, E.164 output and a validity check.
Argentina+54
Australia+61
Austria+43
Bahrain+973
Bangladesh+880
Belgium+32
Brazil+55
Bulgaria+359
Canada+1
Chile+56
China+86
Colombia+57
Costa Rica+506
Croatia+385
Czechia+420
Denmark+45
Egypt+20
Finland+358
France+33
Germany+49
Ghana+233
Greece+30
Hong Kong+852
Hungary+36
Iceland+354
India+91
Indonesia+62
Ireland+353
Israel+972
Italy+39
Japan+81
Kenya+254
Kuwait+965
Luxembourg+352
Malaysia+60
Mexico+52
Morocco+212
Netherlands+31
New Zealand+64
Nigeria+234
Norway+47
Pakistan+92
Peru+51
Philippines+63
Poland+48
Portugal+351
Qatar+974
Romania+40
Russia+7
Saudi Arabia+966
Serbia+381
Singapore+65
Slovakia+421
Slovenia+386
South Africa+27
South Korea+82
Spain+34
Sri Lanka+94
Sweden+46
Switzerland+41
Taiwan+886
Thailand+66
Turkey+90
Ukraine+380
United Arab Emirates+971
United Kingdom+44
United States+1
Uruguay+598
Vietnam+84
We text a code to this number. Type +33… to switch country.
Nothing entered
Argentina+54
Australia+61
Austria+43
Bahrain+973
Bangladesh+880
Belgium+32
Brazil+55
Bulgaria+359
Canada+1
Chile+56
China+86
Colombia+57
Costa Rica+506
Croatia+385
Czechia+420
Denmark+45
Egypt+20
Finland+358
France+33
Germany+49
Ghana+233
Greece+30
Hong Kong+852
Hungary+36
Iceland+354
India+91
Indonesia+62
Ireland+353
Israel+972
Italy+39
Japan+81
Kenya+254
Kuwait+965
Luxembourg+352
Malaysia+60
Mexico+52
Morocco+212
Netherlands+31
New Zealand+64
Nigeria+234
Norway+47
Pakistan+92
Peru+51
Philippines+63
Poland+48
Portugal+351
Qatar+974
Romania+40
Russia+7
Saudi Arabia+966
Serbia+381
Singapore+65
Slovakia+421
Slovenia+386
South Africa+27
South Korea+82
Spain+34
Sri Lanka+94
Sweden+46
Switzerland+41
Taiwan+886
Thailand+66
Turkey+90
Ukraine+380
United Arab Emirates+971
United Kingdom+44
United States+1
Uruguay+598
Vietnam+84
Argentina+54
Australia+61
Austria+43
Bahrain+973
Bangladesh+880
Belgium+32
Brazil+55
Bulgaria+359
Canada+1
Chile+56
China+86
Colombia+57
Costa Rica+506
Croatia+385
Czechia+420
Denmark+45
Egypt+20
Finland+358
France+33
Germany+49
Ghana+233
Greece+30
Hong Kong+852
Hungary+36
Iceland+354
India+91
Indonesia+62
Ireland+353
Israel+972
Italy+39
Japan+81
Kenya+254
Kuwait+965
Luxembourg+352
Malaysia+60
Mexico+52
Morocco+212
Netherlands+31
New Zealand+64
Nigeria+234
Norway+47
Pakistan+92
Peru+51
Philippines+63
Poland+48
Portugal+351
Qatar+974
Romania+40
Russia+7
Saudi Arabia+966
Serbia+381
Singapore+65
Slovakia+421
Slovenia+386
South Africa+27
South Korea+82
Spain+34
Sri Lanka+94
Sweden+46
Switzerland+41
Taiwan+886
Thailand+66
Turkey+90
Ukraine+380
United Arab Emirates+971
United Kingdom+44
United States+1
Uruguay+598
Vietnam+84
Usage
use hydroxy_leptos::phone_field::{PhoneField, PhoneValue};
use leptos::prelude::*;
pub fn demo() -> AnyView {
let (phone, set_phone) = signal(PhoneValue { e164: None, valid: false });
let readout = move || {
let p = phone.get();
match p.e164 {
Some(n) if p.valid => format!("{n} looks valid"),
Some(n) => format!("{n} is incomplete"),
None => "Nothing entered".to_string(),
}
};
view! {
<div style="display: grid; gap: var(--space-8); max-width: 360px;">
<div style="display: grid; gap: var(--space-2);">
<PhoneField
label="Mobile number"
default_country="GB"
hint="We text a code to this number. Type +33… to switch country."
name="mobile"
on_value_change=move |v| set_phone.set(v)
/>
<p style="margin: 0; font: var(--text-xs); color: var(--text-3);">{readout}</p>
</div>
<PhoneField label="Support line" default_value="+12015550123" read_only=true />
<PhoneField label="Fax" default_country="JP" disabled=true />
</div>
}
.into_any()
}use dioxus::prelude::*;
use hydroxy_dioxus::phone_field::{PhoneField, PhoneValue};
#[component]
pub fn PhoneFieldDemo() -> Element {
let mut phone = use_signal(|| PhoneValue { e164: None, valid: false });
let readout = match phone() {
PhoneValue { e164: Some(n), valid: true } => format!("{n} looks valid"),
PhoneValue { e164: Some(n), valid: false } => format!("{n} is incomplete"),
PhoneValue { e164: None, .. } => "Nothing entered".to_string(),
};
rsx! {
div { style: "display: grid; gap: var(--space-8); max-width: 360px;",
div { style: "display: grid; gap: var(--space-2);",
PhoneField {
label: "Mobile number",
default_country: "GB",
hint: "We text a code to this number. Type +33… to switch country.",
name: "mobile",
on_value_change: move |v| phone.set(v),
}
p { style: "margin: 0; font: var(--text-xs); color: var(--text-3);", "{readout}" }
}
PhoneField { label: "Support line", default_value: "+12015550123", read_only: true }
PhoneField { label: "Fax", default_country: "JP", disabled: true }
}
}
}
Anatomy
| Component | data-part | Renders |
|---|---|---|
PhoneField | root | Wrapper. data-disabled, data-readonly, data-invalid |
PhoneField | label | <label for> the number |
PhoneField | field | Bordered row and the picker's anchor |
PhoneField | trigger | Country button: flag, dial code. aria-haspopup=dialog |
PhoneField | control | type=tel input, autocomplete=tel-national |
PhoneField | picker | popover=auto, role=dialog |
PhoneField | search | role=combobox with aria-activedescendant |
PhoneField | listbox / option | Countries: flag, name, dial code |
PhoneField | status | Polite count of matching countries |
PhoneField | hint / error | Help text, or the error once the field is left invalid |
Keyboard
| Key | Does |
|---|---|
ArrowDown / ArrowUp on the button | Open the country list |
Type in the search | Filter by name, ISO code or +dial code |
ArrowDown / ArrowUp | Move through countries |
Enter | Pick the highlighted country and return to the number |
Escape | Close the list and return to the button |
+ in the number | Type or paste an international number to switch country |
Props
| Prop | Type | Notes |
|---|---|---|
label | String | Required. Visible label |
value / default_value | Option<String> | E.164, such as +447400123456 |
default_country | String | ISO code when there is no value. Default US |
on_value_change | Callback<PhoneValue> | { e164, valid } on every change |
on_country_change | Callback<String> | ISO code |
hint | String | Help text, replaced by the error while invalid |
disabled / read_only / required | bool | Native states |
name | String | Submits E.164 |