npm package: @300codes/astro-icon
Description: Vue icon component for Astro with SSR support
Author: Adam Kanigowski
Latest version: 1.0.4

# @300codes/astro-icon

Vue 3 icon component for Astro with full SSR and Tailwind CSS support.

## Installation

```bash
npm install @300codes/astro-icon
```

### Requirements

- Astro `^4.0.0` || `^5.0.0`
- Vue `^3.0.0`
- Tailwind CSS (for size utility classes)

### Tailwind CSS configuration

Tailwind does not scan `node_modules` by default, so the size utility classes from this library won't be generated unless you explicitly include it.

**Tailwind v4** (with `@tailwindcss/vite`) — add `@source` in your CSS:

```css
/* src/styles/global.css */
@import 'tailwindcss';
@source '../../node_modules/@300codes/astro-icon/dist';
```

**Tailwind v3** — add the path to the `content` array in your config:

```js
// tailwind.config.mjs
export default {
  content: [
    './src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}',
    './node_modules/@300codes/astro-icon/dist/**/*.js',
  ],
};
```

This ensures Tailwind picks up classes like `w-6`, `min-w-6`, `h-6`, etc. used by the component.

## Usage in Astro

### SSR only (no client-side JavaScript)

Icon rendered on the server without hydration — the lightest option:

```astro
---
import { BaseIcon } from '@300codes/astro-icon';
---

<BaseIcon name="arrow-right" />
<BaseIcon name="star" size="lg" />
```

### Hydrate on page load

Icon rendered on the server and immediately hydrated on the client — useful when the `name` prop may change dynamically:

```astro
---
import { BaseIcon } from '@300codes/astro-icon';
---

<BaseIcon client:load name="arrow-right" size="md" />
```

### Hydrate when visible

Icon rendered on the server, hydrated only when it enters the viewport — optimal for icons below the fold:

```astro
---
import { BaseIcon } from '@300codes/astro-icon';
---

<BaseIcon client:visible name="star" size="xl" />
```

### Client only (no SSR)

Icon rendered exclusively on the client — it will not appear in the server HTML:

```astro
---
import { BaseIcon } from '@300codes/astro-icon';
---

<BaseIcon client:only="vue" name="logo" size="2xl" icon-path="/custom-icons" />
```

## Usage in Vue

Standard usage inside a Vue component:

```vue
<script setup>
import { BaseIcon } from '@300codes/astro-icon';
</script>

<template>
  <BaseIcon name="arrow-right" />
  <BaseIcon name="star" size="lg" />
  <BaseIcon name="logo" size="auto" icon-path="/custom-icons" />
</template>
```

## Props

| Prop       | Type       | Default    | Description                                    |
|------------|------------|------------|------------------------------------------------|
| `name`     | `string`   | (required) | SVG file name (without the `.svg` extension)   |
| `size`     | `IconSize` | `'md'`     | Icon size                                      |
| `iconPath` | `string`   | `'/icons'` | Path to the icons directory inside `public/`   |

## Sizes (`IconSize`)

The component uses Tailwind CSS classes for sizing. The classes are not compiled within the library — they are generated by the Tailwind configuration in your Astro project.

| Size  | Pixels | Tailwind classes      |
|-------|--------|-----------------------|
| `2xs` | 12px   | `w-3 min-w-3 h-3`    |
| `xs`  | 16px   | `w-4 min-w-4 h-4`    |
| `sm`  | 20px   | `w-5 min-w-5 h-5`    |
| `md`  | 24px   | `w-6 min-w-6 h-6`    |
| `lg`  | 32px   | `w-8 min-w-8 h-8`    |
| `xl`  | 40px   | `w-10 min-w-10 h-10` |
| `2xl` | 48px   | `w-12 min-w-12 h-12` |
| `3xl` | 64px   | `w-16 min-w-16 h-16` |
| `auto`| —      | (no classes)          |

The `auto` size does not apply any classes — the icon will adapt to its parent's dimensions.

## Types

The library exports the `IconSize` type for use in your code:

```ts
import { BaseIcon, type IconSize } from '@300codes/astro-icon';

const size: IconSize = 'lg';
```

## Where to place icons

SVG files should be placed in the `public/` directory of your Astro project. The default path is `public/icons/`:

```
my-astro-project/
  public/
    icons/          <-- default path (iconPath="/icons")
      arrow-right.svg
      star.svg
      logo.svg
```

Pass the file name (without `.svg`) as the `name` prop:

```vue
<!-- Loads public/icons/arrow-right.svg -->
<BaseIcon name="arrow-right" />
```

### Custom path

If you keep icons in a different directory, use the `iconPath` prop:

```vue
<!-- Loads public/assets/ui/star.svg -->
<BaseIcon name="star" icon-path="/assets/ui" />
```

## How the component works

1. **SSR (server)** — during server-side rendering, the component reads the SVG file directly from the filesystem (`public/iconPath/name.svg`) and injects its content into the HTML. This makes the icon visible immediately, without waiting for client-side JavaScript.

2. **Client** — after the component is mounted in the browser, if the SVG content has not been loaded yet (e.g. during client-side navigation), it fetches it via `fetch`.

3. **Reactivity** — changing the `name` prop automatically fetches and displays the new icon.

4. **Fallback** — if the icon is not found, the component displays a placeholder.

## SVG — set `fill` to `currentColor`

For icons to properly inherit the text color from CSS (e.g. via Tailwind's `text-red-500`), SVG files **must** have the `fill` attribute set to `currentColor`:

```xml
<!-- arrow-right.svg -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
  <path d="M..." />
</svg>
```

If the SVG has `fill` set to a specific color (e.g. `#000000`), changing the color via CSS will not work. The same applies to the `stroke` attribute — if the icon uses strokes, set `stroke="currentColor"`.

## License

MIT