@cekemail/widget
v1.2.4
Published
Email validation widget for CekEmail - validates email addresses in real-time on your website
Maintainers
Readme
@cekemail/widget
Official email-validation widget for CekEmail — real-time email verification for your forms.
Installation
Get an API key at cekemail.com.
CDN
<script>
CekEmail_APIKEY = 'wk_xxxxxxxxxxxxx';
</script>
<script src="https://static.cekemail.com/widget/v1/cekemail.min.js"></script>widget/v1/cekemail.min.jsserves the latest 1.x release: you get every 1.x fix and feature automatically, but never a breaking 2.x release. Prefer it in production.widget/cekemail.min.jsalways serves the latest release, including future major releases with breaking changes.
Alternative CDN: the package is also available on jsDelivr at
https://cdn.jsdelivr.net/npm/@cekemail/widget@1. The@1pins the major version the same wayv1/does. To lock an exact release, use a full version such as@cekemail/[email protected].
NPM
For bundlers:
npm install @cekemail/widgetUsage
CDN (Simple Embed)
Add this code to your website, just before the closing </body> tag:
<script>
CekEmail_APIKEY = 'wk_xxxxxxxxxxxxx';
</script>
<script src="https://static.cekemail.com/widget/v1/cekemail.min.js"></script>The widget will automatically:
- Detect all
<input type="email">elements - Validate emails when users leave the field (blur)
- Display visual indicators (✓ for valid, ✗ for invalid)
NPM (ES Module)
import { CekEmail } from '@cekemail/widget';
const widget = new CekEmail();
widget.init({
apiKey: 'wk_xxxxxxxxxxxxx',
debounce: 500, // optional: delay before validation (ms)
showIndicator: true, // optional: show ✓/✗ icons
validateOnBlur: true, // optional: validate on blur
validateOnChange: false, // optional: validate while typing
});CommonJS
const { CekEmail } = require('@cekemail/widget');
const widget = new CekEmail();
widget.init({ apiKey: 'wk_xxxxxxxxxxxxx' });Configuration
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| apiKey | string | null | Widget API key (required) |
| apiUrl | string | https://api.cekemail.com/v1/widget/email-check | API endpoint |
| debounce | number | 800 | Delay before validation (ms) |
| showIndicator | boolean | true | Show validation icons |
| showSuggestion | boolean | true | Show the "did you mean" hint under the input |
| autoAttach | boolean | true | Auto-attach to email inputs |
| validateOnBlur | boolean | true | Validate when field loses focus |
| validateOnChange | boolean | false | Validate while typing |
| cssClass | object | See below | Custom CSS class names |
| locale | string | 'en' | Language for built-in messages (en, id) |
| messages | object \| function | null | Custom messages keyed by reason code, or a function (see Localization) |
Self-hosted API
The widget always calls https://api.cekemail.com/v1/widget/email-check, wherever the script itself is loaded from. If you run your own CekEmail API, set the endpoint explicitly with CekEmail_API_URL:
<script>
CekEmail_APIKEY = 'wk_xxxxxxxxxxxxx';
CekEmail_API_URL = 'https://email-check.example.com/v1/widget/email-check';
</script>
<script src="https://static.cekemail.com/widget/v1/cekemail.min.js"></script>With npm, pass apiUrl to init() instead:
widget.init({
apiKey: 'wk_xxxxxxxxxxxxx',
apiUrl: 'https://email-check.example.com/v1/widget/email-check',
});CSS Classes
{
valid: 'cekemail-valid',
invalid: 'cekemail-invalid',
checking: 'cekemail-checking',
wrapper: 'cekemail-wrapper',
indicator: 'cekemail-indicator',
suggestion: 'cekemail-suggestion',
}Localization
The widget ships with English and Indonesian messages. Pick one with locale, override any string with messages, or supply a function for full control. Messages are shown as the input's tooltip and in the data-cekemail-message attribute.
<script>
CekEmail_APIKEY = 'wk_xxxxxxxxxxxxx';
CekEmail_LOCALE = 'id';
CekEmail_MESSAGES = { mailbox_not_found: 'Alamat ini tidak ditemukan' };
</script>
<script src="https://static.cekemail.com/widget/v1/cekemail.min.js"></script>widget.init({
apiKey: 'wk_xxxxxxxxxxxxx',
locale: 'en',
messages: {
invalid_format: 'Please enter a valid email address',
disposable: 'Temporary email providers are not allowed',
},
});
// Function form: return a string, or a falsy value to fall back to the defaults
widget.init({
apiKey: 'wk_xxxxxxxxxxxxx',
messages: (result, isValid) => (isValid ? null : `We could not verify ${result.input}`),
});Messages are looked up by the API's reason_code. Keys you can override:
| Key | When it is shown |
|-----|------------------|
| checking | While a lookup is in progress |
| did_you_mean | The API returned a likely correction; :suggestion is the corrected address |
| invalid_format | The address failed the local format check |
| mailbox_exists | The mailbox exists and accepts mail |
| mailbox_not_found | The mail server reported the mailbox does not exist |
| mailbox_full | The mailbox is over quota |
| mailbox_not_allowed | The mail server does not accept this mailbox name |
| no_mx_records | The domain has no mail server |
| disposable | The domain is a disposable email provider |
| catch_all | The domain accepts any address |
| greylisted | The mail server asked for a retry |
| smtp_unreachable | No mail server could be reached |
| server_temporarily_unavailable | The mail server returned a temporary failure |
| sender_blocked | The mail server refused the verification |
| policy_rejected | The mail server rejected the address for policy reasons |
| unknown | The verification could not be completed |
| valid / invalid | Generic fallbacks when no code matches |
Did you mean
When the API returns a suggestion (for example [email protected] for [email protected]), the widget shows a small hint under the input. Clicking the suggested address fills the field and validates it again. Translate it with the did_you_mean message, where :suggestion is replaced by the corrected address.
<script>
CekEmail_APIKEY = 'wk_xxxxxxxxxxxxx';
CekEmail_LOCALE = 'id';
CekEmail_MESSAGES = { did_you_mean: 'Mungkin maksud Anda :suggestion?' };
</script>
<script src="https://static.cekemail.com/widget/v1/cekemail.min.js"></script>Set showSuggestion: false to keep the suggestion out of the DOM and render your own hint from the cekemail:validated event, which carries result.suggestion.
API
init(config?)
Initialize the widget with optional configuration.
widget.init({
apiKey: 'wk_xxxxxxxxxxxxx',
debounce: 500,
});setApiKey(key)
Replace the API key used for subsequent requests. Inputs stay attached and cached results are kept.
widget.setApiKey('wk_yyyyyyyyyyyyy');Rotating keys
If your page hands out short-lived keys, the script does not need a key at load time. Load it without CekEmail_APIKEY, then call init() once the first key arrives and setApiKey() whenever it is replaced:
// First key: initialize the widget that was loaded without one
window.CekEmail.init({ apiKey: firstKey });
// Later: rotate without re-initializing
window.CekEmail.setApiKey(nextKey);Calling setApiKey() before init() makes that key the one init() uses.
validate(input | email)
Validate an input element or email string.
// Validate input element
const input = document.querySelector('#email');
widget.validate(input);
// Validate email string
const result = await widget.validate('[email protected]');
console.log(result.is_valid);validateEmailDirectly(email)
Validate an email string and return the result.
const result = await widget.validateEmailDirectly('[email protected]');
console.log(result);
// {
// is_valid: true,
// is_reachable: true,
// is_disposable_email: false,
// reason: 'Email is valid'
// }attachToInput(input)
Manually attach the widget to an input element.
const input = document.querySelector('#my-email');
widget.attachToInput(input);clearValidationState(input)
Clear validation state from an input.
widget.clearValidationState(input);clearCache()
Clear the validation result cache.
widget.clearCache();getCacheSize()
Get the number of cached validation results.
console.log(widget.getCacheSize());Events
cekemail:validated
Fired when an email is validated.
document.addEventListener('cekemail:validated', (event) => {
const { input, result, isValid } = event.detail;
console.log('Email:', input.value);
console.log('Valid:', isValid);
console.log('Result:', result);
});Disabling on Specific Inputs
Add data-cekemail-disable to prevent validation:
<input type="email" data-cekemail-disable />CSS Styling
The widget adds classes to inputs based on validation state:
/* Valid email */
input.cekemail-valid {
border-color: #22c55e !important;
}
/* Invalid email */
input.cekemail-invalid {
border-color: #ef4444 !important;
}
/* Checking email */
input.cekemail-checking {
border-color: #3b82f6 !important;
}Override with your own styles:
input.cekemail-valid {
border: 2px solid green;
background-color: #f0fff0;
}
input.cekemail-invalid {
border: 2px solid red;
background-color: #fff0f0;
}TypeScript
Full TypeScript support with exported types:
import {
CekEmail,
CekEmailConfig,
ValidationResult,
ValidatedEventDetail,
} from '@cekemail/widget';
const config: Partial<CekEmailConfig> = {
apiKey: 'wk_xxxxxxxxxxxxx',
debounce: 500,
};
const widget = new CekEmail();
widget.init(config);
// Type-safe validation result
const result: ValidationResult = await widget.validateEmailDirectly('[email protected]');Browser Support
- Chrome (last 2 versions)
- Firefox (last 2 versions)
- Safari (last 2 versions)
- Edge (last 2 versions)
Publishing
For maintainers:
npm login
npm publishnpm publish runs the build first (prepublishOnly), and publishConfig.access makes the scoped package public. Bump version in package.json before publishing.
Pushing to main or publishing a GitHub release deploys the build to static.cekemail.com/widget/ and purges the Cloudflare cache for those files.
jsDelivr serves the new npm version within minutes. To refresh the @1 alias right away, purge it:
https://purge.jsdelivr.net/npm/@cekemail/widget@1Links
License
MIT
