Skip to content

API reference

Everything kanji.js 1.6.2 exports. The default export is the Kanji class, and all of its methods are static.

Kanji.getDetails()#

Kanji.getDetails(character: string)→ Word | null

Returns the dictionary entry whose literal is exactly character, or null if there isn't one.

NameTypeDescription
characterstringA single kanji, such as '日'. The match is exact: no trimming, no variant folding, and no lookup by reading or meaning.
Kanji.getDetails('日') // { literal: '日', meanings: ['day', 'sun', …], … }
Kanji.getDetails('日本') // null (only single characters are entries)
Kanji.getDetails('ア') // null (kana are not in the dictionary)

The returned object is the dictionary's own entry, not a copy. Don't change it.

Kanji.search(options?: SearchOptions)→ Word[]

Scans every entry in the dictionary. It drops the entries that fail the filters, scores the rest against the ranking hints, and returns them best match first.

NameTypeDescription
gradenumber | RangeOptionFilter. Keep entries with this school grade, or with a grade inside the range. See grade values.
jlptnumber | RangeOptionFilter. Keep entries with this JLPT level, or with a level inside the range. Levels use the old 1–4 scale.
meaningstringRanking hint. An English word or phrase, fuzzy-matched against each entry's meanings.
romajistringRanking hint. A reading in romaji (or kana), fuzzy-matched against the on and kun readings.
sortbooleanDefault true. Set it to false to skip sorting and return matches in dictionary order.

A RangeOption is { min?: number, max?: number }. Both ends are inclusive.

Kanji.search({ grade: 2 }) // grade 2 only (160 characters)
Kanji.search({ jlpt: { min: 3 } }) // JLPT 3 and 4 (284 characters)
Kanji.search({ grade: 1, meaning: 'water' })[0] // 水
Kanji.search({ romaji: 'hi', jlpt: 4 })[0] // 火

Filters#

grade and jlpt are the only options that remove results. Each is checked in one of two ways:

  • A number keeps entries whose value is exactly that number. Entries with null are always dropped.
  • A range drops entries below min or above max. A min also drops entries with null, but a max on its own doesn't, because the library compares null > max and that is false.
Kanji.search({ grade: { max: 6 } }).length // 11117, includes ungraded
Kanji.search({ grade: { min: 1, max: 6 } }).length // 1006, school kanji only

Ranking#

Every entry that passes the filters gets a score:

  1. It starts at 1, just for passing the filters.
  2. If you set meaning, the library fuzzy-matches it against the entry's meanings with fuzzyset.js. A similarity of at least 0.75 adds that similarity (0.75–1) to the score.
  3. If you set romaji, the library converts it to katakana and matches it against onyomi. It also converts it to hiragana and matches it against kunyomi, using WanaKana. Each reading list that matches with a similarity of at least 0.75 adds its similarity, so a romaji match can add up to 2.

With sort on, results are ordered from the highest score down. Entries with the same score stay in dictionary order. Because every entry that passes the filters scores at least 1, ranking hints never remove results. A search with only meaning or romaji returns all 13,108 entries.

// Top five results for a meaning
Kanji.search({ meaning: 'water' }).slice(0, 5).map(k => k.literal)
// ['水', '霑', '氵', '潑', '㴑']
// Kana input works too, since WanaKana passes kana through
Kanji.search({ romaji: 'みず' })[0].literal // '水'

Scores aren't returned. To keep only real matches, check the fields yourself. See Find characters with an exact reading.

Performance#

search() builds new fuzzy-match sets for every entry on every call, so a search with meaning or romaji takes a noticeable moment: about 0.3 seconds in Node.js 22 on a recent laptop. Searches with only filters are much faster. In a UI, debounce input, or run the search in a Web Worker.

Kanji.random()#

Kanji.random()→ Word

Returns a random entry from the whole dictionary. It takes no options, and the result is mostly rare characters, since about 77% of entries have no grade or JLPT level. It uses Math.random(), so it isn't suitable for anything security-related.

Kanji.random().literal // e.g. '幬'

Kanji.dump()#

Kanji.dump()→ Word[]

Returns the full dictionary: 13,108 entries in KANJIDIC2 order. Every call returns the same array, the library's own copy, so treat it as read-only.

const all = Kanji.dump()
all.length // 13108
Kanji.dump() === all // true
const sorted = [...all].sort((a, b) => a.stroke_count - b.stroke_count) // copy first

Instance properties#

You don't need an instance to use the library. Creating one gives you its name and version:

const k = new Kanji()
k.name // 'Kanji'
k.version // '1.6.2'

Types#

These are the shapes the library actually returns. They differ from the bundled index.d.ts in the fields marked null. Copy them into your project if you want TypeScript to catch the missing values.

kanji-types.ts
export interface Word {
literal: string // the character, e.g. '日'
meanings: string[] // English meanings, may be empty
onyomi: string[] // on readings in katakana, may be empty
kunyomi: string[] // kun readings in hiragana, may be empty
stroke_count: number
grade: number | null // 1–6, 8, 9 or 10, or null
jlpt: number | null // 1–4 (old scale), or null
freq: number | null // 1–2501, or null
}
export interface RangeOption {
min?: number // inclusive
max?: number // inclusive
}
export interface SearchOptions {
grade?: number | RangeOption
jlpt?: number | RangeOption
meaning?: string
romaji?: string
sort?: boolean // default true
}

The Character data page describes each field and its values.

Known issues#

These are current behaviors of version 1.6.2. They may change in a future release.

  • The bundled types don't allow null from getDetails(), or in grade, jlpt and freq.
  • random() never returns the last dictionary entry (頻).
  • A range with only max includes entries with no value. A min or max of 0 is ignored.
  • meaning and romaji rank results but don't filter them.