# API Reference

Complete API documentation for `@marianmeres/icons-fns`.

The package is almost entirely generated: **19,199 icon functions**, each living in its own
module behind its own import subpath, so a bundler only ever sees the icons you actually
reference. The hand-written surface is deliberately tiny — two entry points, one factory,
five lookup functions and five types.

| Entry point           | Contains                                                                                                                                                                                           |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `.` (root)            | [`icon()`](#iconsize-strokewidth-head-rest), [`IconProps`](#iconprops), [`IconFn`](#iconfn) — no icons                                                                                             |
| `./search`            | [`searchIcons`](#searchiconsquery-options) · [`listIcons`](#listiconsfamily) · [`findIcon`](#findiconname) · [`listFamilies`](#listfamilies) · [`listFamilyInfo`](#listfamilyinfo) and their types |
| `./<family>/<fnName>` | one [icon function](#icon-functions) — 19,199 subpaths                                                                                                                                             |

## Table of Contents

- [Import specifiers](#import-specifiers)
- [Icon functions](#icon-functions)
  - [Signature](#signature)
  - [Props](#props)
  - [Emitted markup](#emitted-markup)
  - [Families](#families)
- [Root export](#root-export)
  - [`icon(size, strokeWidth, head, rest)`](#iconsize-strokewidth-head-rest)
  - [Types](#types): [`IconProps`](#iconprops) · [`IconFn`](#iconfn)
- [`./search`](#search)
  - [Functions](#functions): [`searchIcons`](#searchiconsquery-options) · [`listIcons`](#listiconsfamily) · [`findIcon`](#findiconname) · [`listFamilies`](#listfamilies) · [`listFamilyInfo`](#listfamilyinfo)
  - [Types](#types-1): [`IconInfo`](#iconinfo) · [`IconFamilyInfo`](#iconfamilyinfo) · [`SearchIconsOptions`](#searchiconsoptions)
- [MCP tools](#mcp-tools)

---

## Import specifiers

An icon's subpath is always `<family>/<functionName>` — the family directory, then the
exported function name spelled exactly. The same specifier works on both registries:

```ts
import { iconLucideArrowUp } from "@marianmeres/icons-fns/lucide/iconLucideArrowUp";
```

On npm the legacy extension-ful form that every release before 6.0 used keeps working too:

```js
import { iconLucideArrowUp } from "@marianmeres/icons-fns/lucide/iconLucideArrowUp.js";
```

| Target   | JSR                                               | npm                                 |
| -------- | ------------------------------------------------- | ----------------------------------- |
| Root     | `@marianmeres/icons-fns`                          | `@marianmeres/icons-fns`            |
| Search   | `@marianmeres/icons-fns/search`                   | `@marianmeres/icons-fns/search`     |
| One icon | `@marianmeres/icons-fns/lucide/iconLucideArrowUp` | same, or `.../iconLucideArrowUp.js` |

JSR forbids wildcard export keys, so `deno.json` carries all 19,201 entries explicitly
(19,199 icons + `.` + `./search`), regenerated by `deno task build`. The npm package uses
subpath patterns instead — two per family, one for each specifier shape.

[`IconInfo.path`](#iconinfo) hands you the `<family>/<functionName>` string directly, which
is the reliable way to construct a specifier programmatically.

---

## Icon functions

### Signature

Every one of the 19,199 icon functions has exactly this type:

```ts
type IconFn = (props?: Partial<IconProps> | null) => string;
```

They are pure: no DOM, no state, no side effects — just a string. `f()`, `f(undefined)`,
`f(null)` and `f({})` all render identical markup.

```ts
import { iconHeroMiniAcademicCap } from "@marianmeres/icons-fns/heroicons/mini/iconHeroMiniAcademicCap";

iconHeroMiniAcademicCap({ class: "inline-block", size: 32, style: "color: blue;" });
// <svg style="color: blue;" class="inline-block" width="32" height="32"
//      viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon">…</svg>
```

### Props

Four keys are consumed by the renderer; **every other key becomes an attribute**.

| Prop            | Type      | Default                 | Behavior                                                                 |
| --------------- | --------- | ----------------------- | ------------------------------------------------------------------------ |
| `size`          | `number`  | the icon's natural size | Sets both `width` and `height`.                                          |
| `class`         | `string`  | —                       | The `class` attribute. Omitted entirely when falsy.                      |
| `style`         | `string`  | —                       | The `style` attribute. Omitted entirely when falsy.                      |
| `strokeWidth`   | `number`  | the family default      | The `stroke-width` attribute. Only [stroke families](#families) emit it. |
| _anything else_ | `unknown` | —                       | Emitted verbatim as `key="value"`.                                       |

**`size` falls back on any falsy value, `strokeWidth` only on `undefined`/`null`.** The
asymmetry is deliberate: a zero-sized icon is meaningless, a zero stroke width is not.

```ts
iconFeatherActivity({ size: 0 }); //  width="24" height="24"  — natural size
iconFeatherActivity({ strokeWidth: 0 }); //  stroke-width="0" — honored
```

**Pass-through is exact-match.** Only the literal keys `class`, `size`, `style` and
`strokeWidth` are withheld; anything else — including near-misses like `className`,
`data-size` and `stroke-style` — is rendered as an attribute. (Releases before 6.0 used an
unanchored regex and silently dropped those three.)

```ts
iconBsArrowUp({ class: "c", style: "s", "data-size": "x" });
// <svg style="s" class="c" width="16" height="16" data-size="x" fill="currentColor" …>
```

Pass-through attributes appear in the props object's own key order, and their values are
interpolated **without escaping** — a value containing `"` will produce broken markup, so
escape untrusted input yourself.

Because [`IconProps`](#iconprops) extends `Record<string, unknown>`, arbitrary keys
type-check without a cast.

### Emitted markup

```
[head]<svg [style ][class ]width height [stroke-width ][pass-through ]<family attributes>>…</svg>
```

In order:

1. **`head`** — markup preceding `<svg`. Only Lucide has one, an
   `<!-- @license lucide-static v1.33.0 - ISC -->` comment. (Font Awesome carries its
   license notice _inside_ the element instead, as the first child node.)
2. **`style`**, then **`class`** — each omitted entirely when falsy.
3. **`width`** and **`height`** — always present, always equal.
4. **`stroke-width`** — only for [stroke families](#families).
5. **Pass-through attributes** — every non-reserved prop.
6. **The icon's own attributes and body** — `viewBox`, `fill`, `stroke`, paths, `</svg>`.
   These are fixed at build time and never vary with props.

```ts
iconLucideArrowUp({ size: 24, strokeWidth: 1.5, "aria-hidden": "true" });
// <!-- @license lucide-static v1.33.0 - ISC --><svg width="24" height="24"
//    stroke-width="1.5" aria-hidden="true"  viewBox="0 0 24 24" fill="none"
//    stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" >…</svg>
```

For the 14,305 icons whose upstream artwork did not change in this release — every family
except Lucide and Font Awesome, both of which were upgraded — the output is byte-identical
to 5.x, locked by 600 golden assertions in `tests/legacy-parity.test.ts`. The one
deliberate difference is the props filter above: keys like `className` that 5.x dropped are
now emitted.

### Families

19 family directories from 8 providers. `prefix` is shared by every function name in the
directory; the rest of the name is the upstream icon name in `PascalCase`.

| Family directory       | Prefix            | Icons | Natural size | `stroke-width` |
| ---------------------- | ----------------- | ----- | ------------ | -------------- |
| `bootstrap`            | `iconBs`          | 2078  | 16           | —              |
| `boxicons/regular`     | `iconBxRegular`   | 814   | 24           | —              |
| `boxicons/solid`       | `iconBxSolid`     | 665   | 24           | —              |
| `bytesize`             | `iconBytesize`    | 101   | 32           | `2`            |
| `feather`              | `iconFeather`     | 287   | 24           | `2`            |
| `font-awesome/brands`  | `iconFaBrand`     | 609   | 24           | —              |
| `font-awesome/regular` | `iconFaRegular`   | 273   | 24           | —              |
| `font-awesome/solid`   | `iconFaSolid`     | 1996  | 24           | —              |
| `heroicons/micro`      | `iconHeroMicro`   | 316   | 16           | —              |
| `heroicons/mini`       | `iconHeroMini`    | 324   | 20           | —              |
| `heroicons/outline`    | `iconHeroOutline` | 324   | 24           | —              |
| `heroicons/solid`      | `iconHeroSolid`   | 324   | 24           | —              |
| `lucide`               | `iconLucide`      | 2016  | 16           | `2`            |
| `phosphor/bold`        | `iconPhBold`      | 1512  | 16           | —              |
| `phosphor/duotone`     | `iconPhDuotone`   | 1512  | 16           | —              |
| `phosphor/fill`        | `iconPhFill`      | 1512  | 16           | —              |
| `phosphor/light`       | `iconPhLight`     | 1512  | 16           | —              |
| `phosphor/regular`     | `iconPhRegular`   | 1512  | 16           | —              |
| `phosphor/thin`        | `iconPhThin`      | 1512  | 16           | —              |

Notes:

- **Natural size** is the fallback for `size`, not the `viewBox`. It is the larger side of
  the upstream `viewBox`, except for Font Awesome (forced to 24), Phosphor and Lucide
  (forced to 16) — so `iconLucideArrowUp()` renders `width="16"` over a `0 0 24 24`
  viewBox.
- Two Bytesize icons deviate: `iconBytesizeGithub` and `iconBytesizeTwitter` have a natural
  size of 64 and a default `stroke-width` of `0`.
- Only **Bytesize, Feather and Lucide** emit `stroke-width` at all; `strokeWidth` passed to
  any other family is silently ignored (it is reserved, so it does not leak through as an
  attribute either).
- These numbers are also available at runtime from
  [`listFamilyInfo()`](#listfamilyinfo).

---

## Root export

```ts
import { icon, type IconFn, type IconProps } from "@marianmeres/icons-fns";
```

The root module carries **no icons** — only the shared renderer and its types.

### `icon(size, strokeWidth, head, rest)`

Builds an icon function from static parts. Every generated icon module is a single call to
this factory; hoisting it here instead of inlining it into ~19k modules is what keeps the
package inside JSR's 20 MiB per-version budget.

**Parameters:**

- `size` (`number`) — Natural size, used for `width`/`height` when `props.size` is falsy.
- `strokeWidth` (`number | null`) — Default `stroke-width`. `null` omits the attribute
  entirely and makes the function ignore `props.strokeWidth`.
- `head` (`string`) — Markup emitted before `<svg`, e.g. a license comment. Use `""` for none.
- `rest` (`string`) — Everything after the generated `<svg` attributes: the icon's own
  attributes, its body, and the closing `</svg>`.

**Returns:** [`IconFn`](#iconfn)

**Example** — wrapping your own SVG so it takes the same props as the bundled icons:

```ts
import { icon } from "@marianmeres/icons-fns";

const iconMyDash = icon(
	24,
	1.5,
	"",
	`viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 12h16"/></svg>`,
);

iconMyDash({ class: "x" });
// <svg class="x" width="24" height="24" stroke-width="1.5" viewBox="0 0 24 24"
//      fill="none" stroke="currentColor"><path d="M4 12h16"/></svg>
```

You rarely need this otherwise — reach for it when you want a project-local icon to honor
the same `size` / `class` / `style` / `strokeWidth` contract.

### Types

#### `IconProps`

```ts
interface IconProps extends Record<string, unknown> {
	/** Both `width` and `height`. Falls back to the icon's natural size. */
	size: number;
	/** The `class` attribute. Omitted entirely when falsy. */
	class: string;
	/** The `style` attribute. Omitted entirely when falsy. */
	style: string;
	/** The `stroke-width` attribute. Only honored by Bytesize, Feather and Lucide. */
	strokeWidth: number;
}
```

Icon functions take `Partial<IconProps>`, so all four are optional. The
`Record<string, unknown>` base is what lets arbitrary attribute keys type-check. See
[Props](#props) for behavior.

#### `IconFn`

```ts
type IconFn = (props?: Partial<IconProps> | null) => string;
```

The signature shared by every icon function in the package, and the return type of
[`icon()`](#iconsize-strokewidth-head-rest).

---

## `./search`

```ts
import { searchIcons } from "@marianmeres/icons-fns/search";
```

With ~19k icons the hard part is finding a name, not rendering it. This is a separate entry
point on purpose: it pulls in the generated index, which the icon modules themselves never
need — importing an icon never costs you the index.

The index is parsed from a compact string on first call and cached for the process. Every
function returns a fresh array, but the [`IconInfo`](#iconinfo) objects inside it come
straight from that cache — treat them as read-only. ([`listFamilyInfo()`](#listfamilyinfo)
is the exception; it copies its objects.)

### Functions

#### `searchIcons(query, options?)`

Finds icons whose **name** matches every whitespace-separated term in `query`,
case-insensitively. Only names are searched — there are no tags, keywords or aliases.

**Parameters:**

- `query` (`string`) — One or more terms, e.g. `"arrow up"` or `"ArrowUp"`. All terms must
  match (as substrings of the full function name, prefix included). An empty query matches
  everything.
- `options` ([`SearchIconsOptions`](#searchiconsoptions), optional)
  - `options.family` (`string`) — Restrict to one family directory, e.g. `"lucide"` or
    `"heroicons/outline"`. An unknown family simply yields no results.
  - `options.limit` (`number`) — Maximum results. Default: `50`. Pass `0` for no limit.

**Returns:** [`IconInfo[]`](#iconinfo) — ranked, then truncated to `limit`.

**Ranking.** The terms are concatenated (`"arrow up"` → `"arrowup"`) and each match is
scored into one of three tiers, best first:

1. The name **ends with** the concatenated terms — i.e. the query is the icon's own trailing
   name (`iconLucideArrowUp`, `iconLucideCircleArrowUp`).
2. The name **contains** the concatenated terms contiguously somewhere else
   (`iconLucideArrowUpCircle`).
3. Everything else — the terms matched, but not contiguously (`iconLucideArrowBigUp`).

Within a tier, results are sorted ascending by name using plain string comparison, so
digits and uppercase letters sort before lowercase ones.

**Example:**

```ts
searchIcons("arrow up", { family: "lucide", limit: 5 });
// [
//   { name: "iconLucideAArrowUp",        family: "lucide", path: "lucide/iconLucideAArrowUp" },
//   { name: "iconLucideArrowUp",         family: "lucide", path: "lucide/iconLucideArrowUp" },
//   { name: "iconLucideBanknoteArrowUp", family: "lucide", path: "lucide/iconLucideBanknoteArrowUp" },
//   { name: "iconLucideCalendarArrowUp", family: "lucide", path: "lucide/iconLucideCalendarArrowUp" },
//   { name: "iconLucideCircleArrowUp",   family: "lucide", path: "lucide/iconLucideCircleArrowUp" },
// ]
```

#### `listIcons(family?)`

Every icon, optionally restricted to one family.

**Parameters:**

- `family` (`string`, optional) — Family directory, e.g. `"phosphor/thin"`. Omit for all
  families. An unknown family returns `[]`.

**Returns:** [`IconInfo[]`](#iconinfo) — 19,199 entries unfiltered; alphabetical within each
family, families in generation order.

**Example:**

```ts
listIcons("bytesize").length; // 101
listIcons("bytesize")[0];
// { name: "iconBytesizeActivity", family: "bytesize", path: "bytesize/iconBytesizeActivity" }
```

#### `findIcon(name)`

Looks up one icon by its exact function name.

**Parameters:**

- `name` (`string`) — e.g. `"iconLucideArrowUp"`. Matched case-sensitively.

**Returns:** [`IconInfo`](#iconinfo) `| undefined`

**Example:**

```ts
findIcon("iconLucideArrowUp");
// { name: "iconLucideArrowUp", family: "lucide", path: "lucide/iconLucideArrowUp" }

findIcon("iconLucideNope"); // undefined
```

Useful as an existence check before building a dynamic import specifier from `path`.

#### `listFamilies()`

**Returns:** `string[]` — the 19 family directories, in generation order:

```ts
[
	"bootstrap",
	"heroicons/micro",
	"heroicons/mini",
	"heroicons/outline",
	"heroicons/solid",
	"bytesize",
	"feather",
	"boxicons/regular",
	"boxicons/solid",
	"font-awesome/regular",
	"font-awesome/solid",
	"font-awesome/brands",
	"phosphor/bold",
	"phosphor/duotone",
	"phosphor/fill",
	"phosphor/light",
	"phosphor/regular",
	"phosphor/thin",
	"lucide",
];
```

#### `listFamilyInfo()`

The same families with their shared function-name prefix and icon count.

**Returns:** [`IconFamilyInfo[]`](#iconfamilyinfo)

**Example:**

```ts
listFamilyInfo()[0]; // { family: "bootstrap", prefix: "iconBs", count: 2078 }

listFamilyInfo().reduce((sum, f) => sum + f.count, 0); // 19199
```

### Types

#### `IconInfo`

```ts
interface IconInfo {
	/** Exported function name, e.g. `iconLucideArrowUp`. */
	name: string;
	/** Family directory, e.g. `lucide` or `phosphor/regular`. */
	family: string;
	/** Import subpath, e.g. `lucide/iconLucideArrowUp`. */
	path: string;
}
```

#### `IconFamilyInfo`

```ts
interface IconFamilyInfo {
	/** Family directory, e.g. `phosphor/duotone`. */
	family: string;
	/** Prefix shared by every function name in the family, e.g. `iconPhDuotone`. */
	prefix: string;
	/** How many icons the family contains. */
	count: number;
}
```

#### `SearchIconsOptions`

```ts
interface SearchIconsOptions {
	/** Restrict to one family, e.g. `lucide` or `heroicons/outline`. */
	family?: string;
	/** Maximum number of results. Defaults to 50; pass `0` for no limit. */
	limit?: number;
}
```

---

## MCP tools

`mcp.ts` exports a `tools: McpToolDefinition[]` array for
[@marianmeres/mcp-server](https://jsr.io/@marianmeres/mcp-server), giving an agent the same
lookup the `./search` entry point gives a program. Every handler returns a JSON string.
It lives in the repository only — it is excluded from the published package, so the
release pulls in no dependencies.

### `search-icons`

Search all ~19k icons by name and get back the exact export name plus the import specifier
for both registries.

| Parameter | Type     | Required | Description                                                                                   |
| --------- | -------- | -------- | --------------------------------------------------------------------------------------------- |
| `query`   | `string` | yes      | One or more terms, e.g. `"arrow up"`. All terms must match.                                   |
| `family`  | `string` | no       | Restrict to one family directory. Validated — an unknown value returns `{ error, families }`. |
| `limit`   | `number` | no       | Maximum results. Default `25`.                                                                |

Result: `{ count, icons: [{ name, family, jsr, npm }] }`, where `jsr` is
`@marianmeres/icons-fns/<path>` and `npm` is the same with a `.js` suffix.

### `render-icon`

Render one icon to its SVG string, to preview what it actually emits.

| Parameter     | Type     | Required | Description                                                             |
| ------------- | -------- | -------- | ----------------------------------------------------------------------- |
| `name`        | `string` | yes      | Exact function name, e.g. `"iconLucideArrowUp"`.                        |
| `size`        | `number` | no       | Width and height in px. Defaults to the icon's natural size.            |
| `class`       | `string` | no       | Value for the `class` attribute.                                        |
| `style`       | `string` | no       | Value for the `style` attribute.                                        |
| `strokeWidth` | `number` | no       | Value for `stroke-width`; honored only by Bytesize, Feather and Lucide. |

Result: `{ name, family, jsr, npm, svg }`. An unknown name returns
`{ error, didYouMean }`, where `didYouMean` is produced by splitting the requested name on
camel-case boundaries and dropping trailing terms until something matches.

### `list-icon-families`

Every family directory with its icon count and function-name prefix — the way to discover
valid `family` values and the style variants a provider offers. Takes no parameters.

Result: `{ total, families: [{ family, prefix, count, example }] }`, where `example` is the
first icon name in the family and `total` is `19199`.

---

See [README.md](README.md) for installation and a quick-start example.
