# &lt;json-viewer&gt; Element

[简体中文](./README.md) | English

> 🌈 A lightweight, modern Web Component for JSON visualization and interaction.

## Features

- 🌟 **Web Component**: Native, framework-agnostic
- 🎨 **Theme**: Light & dark mode
- 📦 **Boxed**: Optional border and padding
- 📋 **Copyable**: One-click copy JSON
- 🔑 **Sort**: Key sorting support
- 🔍 **Expand Depth**: Control initial expand level
- 🧩 **Custom Copy Button**: Slot for custom copy button
- 🧬 **Type Highlight**: Colorful type highlighting
- 🛠️ **Custom Events**: Listen for copy/toggle events

## Usage

### Install

```bash
npm install json-viewer-element
```

### Import

#### As a module

```js
import 'json-viewer-element'
```

#### UMD (CDN)

```html
<script src="https://unpkg.com/json-viewer-element/dist/json-viewer-element.umd.js"></script>
```

### Basic Example

Set value by script:

```html
<json-viewer id="viewer" boxed copyable sort expand-depth="2" theme="dark"></json-viewer>
<script>
  document.getElementById('viewer').value = { hello: "world", arr: [1,2,3] };
</script>
```

Set value by attribute:

```html
<json-viewer value='{"hello":"world","arr":[1,2,3]}' boxed copyable sort expand-depth="2" theme="dark"></json-viewer>
```

Use in Vue framework:

Vue 2/3 Options API:

```vue
<template>
  <json-viewer :value="JSON.stringify(json)" boxed copyable sort expand-depth="2" theme="dark"></json-viewer>
</template>

<script>
export default {
  data() {
    return {
      json: { hello: "world", arr: [1,2,3] },
    }
  },
}
</script>
```

Vue 3 composition API:

```vue
<script lang="ts" setup>
import { ref } from 'vue'
const json = ref({ hello: "world", arr: [1,2,3] })
</script>

<template>
  <json-viewer :value="JSON.stringify(json)" boxed copyable sort expand-depth="2" theme="dark"></json-viewer>
</template>
```

> [!TIP]
>
> [Skipping Component Resolution](https://vuejs.org/guide/extras/web-components.html#skipping-component-resolution)
>
> To let Vue know that certain elements should be treated as custom elements and skip component resolution, we can specify the [`compilerOptions.isCustomElement` option](https://vuejs.org/api/application.html#app-config-compileroptions).

```js
// vite.config.js
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'

export default {
  plugins: [
    vue({
      template: {
        compilerOptions: {
          // treat all tags with a dash as custom elements
          isCustomElement: tag => tag.includes('-')
        }
      }
    }),
    vueJsx({
      // treat all tags with a dash as custom elements
      isCustomElement: tag => tag.includes('-')
    }),
  ]
}
```

If you're using ESLint with Vue, you may need to configure it to ignore the custom element:

```js
// eslint.config.js
export default {
  rules: {
    'vue/component-name-in-template-casing': [
      'warn',
      'PascalCase',
      {
        registeredComponentsOnly: false,
        ignores: ['/^icon-/', 'json-viewer'],
      },
    ],
  },
}
```

## Props

> [!TIP]
> When using with frameworks like Vue, you should pass value and copyable props as strings.

| Prop         | Type                                       | Default | Description                                                 |
| :----------- | :----------------------------------------- | :------ | :---------------------------------------------------------- |
| value        | object / array / string / number / boolean | null    | JSON data                                                   |
| expand-depth | number                                     | 1       | Initial expand depth                                        |
| copyable     | boolean / CopyableOptions                  | false   | Enable copy button or custom copy button config (see below) |
| sort         | boolean                                    | false   | Whether to sort object keys                                 |
| boxed        | boolean                                    | false   | Whether to show border and padding                          |
| theme        | 'light' / 'dark'                           | 'light' | Theme                                                       |
| parse        | boolean                                    | true    | Whether to parse string value as JSON                       |

### CopyableOptions

| Prop        | Type              | Default   | Description                        |
| :---------- | :---------------- | :-------- | :---------------------------------- |
| copyText    | string            | Copy      | Text shown on the copy button       |
| copiedText  | string            | Copied    | Text shown after successful copy    |
| timeout     | number            | 2000      | How long to show copiedText (ms)    |
| align       | 'left' / 'right'  | right     | Copy button alignment               |

## Events

| Event        | Description              |
| :----------- | :----------------------- |
| copy-success | Fired after copy success |
| copy-error   | Fired after copy failure |
| toggle       | Node expand/collapse     |

## Slots

Custom copy button:

```html
<json-viewer copyable>
  <button slot="copy-button">Copy JSON</button>
</json-viewer>
```

## License

[MIT](https://opensource.org/licenses/MIT)

Copyright (c) 2025-present [Lruihao](https://github.com/Lruihao)
