{"id":28684979,"url":"https://github.com/huyparody/otptextfield","last_synced_at":"2026-05-16T17:37:23.575Z","repository":{"id":298676103,"uuid":"1000695957","full_name":"huyparody/OTPTextField","owner":"huyparody","description":"A customizable SwiftUI OTP input field with underlined and rounded styles, supporting validation states, animation, and styling options.","archived":false,"fork":false,"pushed_at":"2025-06-12T08:43:52.000Z","size":643,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-12T09:43:37.901Z","etag":null,"topics":["2fa","authentication","custominput","ios","onetimepassword","otp","spm","swiftpackage","swiftui","textfield","uicomponent"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/huyparody.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-12T07:24:00.000Z","updated_at":"2025-06-12T09:25:22.000Z","dependencies_parsed_at":"2025-06-12T09:43:43.665Z","dependency_job_id":"953b584c-7e69-4179-a11f-343c73f72a7f","html_url":"https://github.com/huyparody/OTPTextField","commit_stats":null,"previous_names":["huyparody/otptextfield"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/huyparody/OTPTextField","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huyparody%2FOTPTextField","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huyparody%2FOTPTextField/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huyparody%2FOTPTextField/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huyparody%2FOTPTextField/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/huyparody","download_url":"https://codeload.github.com/huyparody/OTPTextField/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huyparody%2FOTPTextField/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279010259,"owners_count":26084719,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-12T02:00:06.719Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["2fa","authentication","custominput","ios","onetimepassword","otp","spm","swiftpackage","swiftui","textfield","uicomponent"],"created_at":"2025-06-14T04:00:17.205Z","updated_at":"2025-10-12T04:32:47.257Z","avatar_url":"https://github.com/huyparody.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OTPTextField for SwiftUI 🔐\n\nA customizable, animated One-Time Password (OTP) input component for SwiftUI that supports rounded borders, underlines, shake animation (invalid otp), blur text replacement (iOS 17+), and more..  \n\nEasily handle 2FA/OTP flows with flexible visual styles and a developer-friendly API.\n\n## ✨ Features\n\n- [x] Underlined and Rounded Border styles\n- [x] Animates on invalid OTP input\n- [x] Fully customizable (font, spacing, border, colors)\n- [x] `@Binding` support for OTP text and state\n- [x] Focus and typing state handling out of the box\n\n---\n\n## 📦 Installation\n\nYou can use Swift Package Manager:\n\n```swift\n.package(url: \"https://github.com/huyparody/OTPTextField.git\", from: \"1.0.0\")\n```\n\n## ⚠️ Notes\n•\tThe shake animation and blur text replacement are only available on iOS 17+\n\n•\tThe rest of the features are compatible with iOS 15+\n\n•\tBuilt with SwiftUI\n\n\n## 🚀 Basic Usage\n\n```swift\nstruct ContentView: View {\n    \n    @State private var text = \"\"\n    @State private var typingState: TypingState = .typing\n\n    var body: some View {\n        OTPTextField(\n            otpMaxDigit: 6,\n            style: .underlined,\n            text: $text,\n            typingState: $typingState,\n            onComplete: {\n                print(\"OTP input complete: \\(text)\")\n            }\n        )\n        .padding()\n    }\n}\n```\n## 🎨 Available Styles\n### ✅ Underlined Style\n\n```swift\nstyle(.underlined)\n```\nVisually shows a line under each digit box.\n\n\u003cimg src=\"Assets/underlined.png\" width=\"375\"/\u003e\n\n---\n\n### 🟦 Rounded Border Style\n\n```swift\nstyle(.roundedBorder)\n```\n\nEach digit is inside a rounded rectangle.\n\n\u003cimg src=\"Assets/rounded.png\" width=\"375\"/\u003e\n\n## ⚙️ Customization\n\n\nUse `OTPTextFieldOptions` to customize colors, font, spacing, and sizing:\n\n| Property               | Type       | Default Value                          | Description                                                                 |\n|------------------------|------------|----------------------------------------|-----------------------------------------------------------------------------|\n| `borderColor`          | `Color`    | `.gray`                                | The border color in the normal state.                                       |\n| `borderCornerRadius`   | `CGFloat`  | `10`                                   | Corner radius for rounded border style.                                     |\n| `borderWidth`          | `CGFloat`  | `1.2`                                  | Border thickness.                                                           |\n| `fillColor`            | `Color`    | `.clear`                               | Background fill color for each OTP field (used with `.roundedBorder`).     |\n| `underlineHeight`      | `CGFloat`  | `1`                                    | Height of the underline (used with `.underlined`).                          |\n| `activeBorderColor`    | `Color`    | `.blue`                                | Border color when the field is focused.                                     |\n| `invalidColor`         | `Color`    | `.red`                                 | Border color used when the input is invalid.                                |\n| `textFieldHeight`      | `CGFloat`  | `50`                                   | Height of each OTP field box.                                               |\n| `textFont`             | `Font`     | `.system(size: 20, weight: .medium)`   | Font used for OTP characters.                                               |\n| `textColor`            | `Color`    | `.primary`                             | Text color for OTP input.                                                   |\n| `underlineSpacing`     | `CGFloat`  | `16`                                   | Spacing between underline segments (used with `.underlined`).               |\n| `roundedCornerSpacing` | `CGFloat`  | `6`                                    | Spacing between boxes (used with `.roundedBorder`).                         |\n\n## ❗ Handling Invalid OTP (requires iOS 17+)\n\nTrigger a visual \"shake\" or invalid animation when OTP is incorrect:\n\n```swift\ntypingState = .invalid\n```\n\nTo reset:\n\n```swift\ntypingState = .typing\n```\n\n\nhttps://github.com/user-attachments/assets/cda317d5-34b8-45bb-9d85-242e87a7f903\n\n\n## 🧠 TypingState Enum\n\n```swift\nenum TypingState {\n    case typing\n    case invalid\n}\n```\n\n## 📋 Advanced Example\n\n```swift\nstruct ContentView: View {\n    \n    @State private var text = \"\"\n    @State private var typingState: TypingState = .typing\n    @State private var selectedStyle: OTPTextFieldStyle = .underlined\n    @State private var simulateInvalidOTP = false\n    \n    let options = OTPTextFieldOptions(borderColor: .red,\n                                      activeBorderColor: .green,\n                                      textFont: .system(size: 24, weight: .bold),\n                                      textColor: .gray)\n    \n    var body: some View {\n        VStack(spacing: 24) {\n            Picker(\"Style\", selection: $selectedStyle) {\n                ForEach(OTPTextFieldStyle.allCases) { style in\n                    Text(style.rawValue.capitalized).tag(style)\n                }\n            }\n            .pickerStyle(.segmented)\n            .padding(.horizontal)\n            \n            OTPTextField(\n                otpMaxDigit: 6,\n                style: selectedStyle,\n                options: options,\n                text: $text,\n                typingState: $typingState,\n                onComplete: {\n                    print(\"Trigger validate otp\")\n                }\n            )\n            .padding(.horizontal)\n            \n            Toggle(\"Simulate OTP invalid\", isOn: $simulateInvalidOTP)\n                .padding()\n                .onChange(of: simulateInvalidOTP) { isOn in\n                    if isOn {\n                        text = (0..\u003c6).map { _ in \"\\(Int.random(in: 0...9))\" }.joined()\n                        typingState = .invalid\n                    } else {\n                        text = \"\"\n                        typingState = .typing\n                    }\n                }\n        }\n        .padding(.vertical)\n    }\n}\n```\n\n## 📄 License\nOTPTextField is released under an MIT license.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhuyparody%2Fotptextfield","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhuyparody%2Fotptextfield","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhuyparody%2Fotptextfield/lists"}