chore: updated readme f9cdc3ed
Steve · 2025-10-18 19:49 1 file(s) · +225 −22
README.md +225 −22
5 5
Interoperable web components for decentralized applications
6 6
7 7
## Overview and Reasoning
8 -
9 8
Some of the first crypto apps we build were in React, and it's possible we might be able to resurrect some of them if we tried. However the unfortunate reality is that web dev frameworks accelerate at an alarming rate, and that goes for blockchain related libraries as well (shudders at the memory of viem v1 -> v2 and ethers v5 -> v6). It doesn't have to be like that though.
10 9
11 10
Web components are independant pieces of Javascript that can be imported to plain HTML but also frameworks as well. They're atomic, existing on their own and able to out-last any framework as long as we keep using Javscript (unfortunately I think that is the case). Some notable existing web component libraries include [Material Web](https://github.com/material-components/material-web) and [Web Awesome](https://github.com/shoelace-style/webawesome).
12 11
13 12
The goal of Norns is to provide the Ethereum ecosystem a set of simple yet powerful web components for building decentralized applications. The advantage we have today is that we've experienced good DX from modern frameworks, so we have the ability to build components that feel familiar to devs building UIs for smart contracts. We will start small but slowly grow the offering as we get a better feel for what devs need; check out the [Roadmap](#roadmap) for more information.
14 13
14 +
## Quickstart
15 +
16 +
1. Initialize `norns` with your package manager of choice
17 +
18 +
```bash
19 +
npx norns-ui@latest init
20 +
```
21 +
22 +
Provide the following information as prompted:
23 +
- Path to where the components will be stored (will use `src/components` by default)
24 +
- If you want to include type definitions
25 +
  - Select framework for type defintions: `typescript`, `react`, `svelte`, `vue`
26 +
27 +
This will create a `norns.json` file in the root of your project with your selections
28 +
29 +
2. Add components
30 +
31 +
Using the `norns.json` the CLI will install them to the provided path in the config.
32 +
33 +
```bash
34 +
npx norns-ui@latest add connect-wallet
35 +
npx norns-ui@latest add contract-call
36 +
npx norns-ui@latest add contract-read
37 +
```
38 +
39 +
3. Use components
40 +
41 +
These web components should work in virtually any framework setup, whether you're in React, Vue, Svelte, or just plain HTML.
42 +
43 +
### HTML/Vanilla JS
44 +
45 +
```html
46 +
<!DOCTYPE html>
47 +
<html lang="en">
48 +
<head>
49 +
  <meta charset="UTF-8">
50 +
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
51 +
  <title>Norns Example</title>
52 +
</head>
53 +
<body>
54 +
  <div class="container">
55 +
    <connect-wallet chain-id="1"></connect-wallet>
56 +
  </div>
57 +
  <script src="./components/connect-wallet.js"></script>
58 +
</body>
59 +
</html>
60 +
```
61 +
62 +
### React
63 +
64 +
```tsx
65 +
import { useEffect, useRef } from "react";
66 +
import "./components/connect-wallet";
67 +
68 +
function App() {
69 +
  const walletRef = useRef<any>(null);
70 +
71 +
  useEffect(() => {
72 +
    const walletElement = walletRef.current;
73 +
    if (!walletElement) return;
74 +
75 +
    walletElement.onWalletConnected = (detail: any) => {
76 +
      console.log("connected: ", detail);
77 +
    };
78 +
  }, []);
79 +
80 +
  return (
81 +
    <div>
82 +
      <connect-wallet chain-id="1" ref={walletRef}></connect-wallet>
83 +
    </div>
84 +
  );
85 +
}
86 +
```
87 +
88 +
### Vue
89 +
90 +
```vue
91 +
<script setup lang="ts">
92 +
import './components/connect-wallet'
93 +
</script>
94 +
95 +
<template>
96 +
  <div>
97 +
    <connect-wallet chain-id="1"></connect-wallet>
98 +
  </div>
99 +
</template>
100 +
```
101 +
102 +
### Svelte
103 +
104 +
```svelte
105 +
<script lang="ts">
106 +
import "./components/connect-wallet";
107 +
</script>
108 +
109 +
<main>
110 +
  <connect-wallet chain-id="1"></connect-wallet>
111 +
</main>
112 +
```
113 +
114 +
### TypeScript
115 +
116 +
```typescript
117 +
import "./components/connect-wallet";
118 +
119 +
const wallet = document.querySelector('connect-wallet');
120 +
wallet?.addEventListener('wallet-connected', (event) => {
121 +
  console.log('Wallet connected:', event.detail);
122 +
});
123 +
124 +
document.body.innerHTML = `
125 +
  <connect-wallet chain-id="1"></connect-wallet>
126 +
`;
127 +
```
128 +
129 +
## Usage
130 +
131 +
Each component has multiple parameters that can be passed in to designate properties like chain ID, contract address, ABI, and more.
132 +
133 +
### `connect-wallet`
134 +
135 +
A Web3 wallet connection component that supports Ethereum wallet integration with ENS resolution, balance display, and multi-chain support.
136 +
137 +
**Attributes:**
138 +
- `chain-id` - Ethereum chain ID in hex or decimal format (default: `"1"` for mainnet)
139 +
- `background` - Background color (default: `"#232323"`)
140 +
- `foreground` - Text color (default: `"#ffffff"`)
141 +
- `primary` - Primary button color (default: `"#5F8787"`)
142 +
- `secondary` - Secondary/hover color (default: `"#6F9797"`)
143 +
- `border-radius` - Border radius for UI elements (default: `"4px"`)
144 +
145 +
**Events:**
146 +
- `wallet-connected` - Fired when wallet is successfully connected
147 +
- `wallet-disconnected` - Fired when wallet is disconnected
148 +
- `wallet-error` - Fired when wallet connection fails
149 +
150 +
**Example:**
151 +
```html
152 +
<connect-wallet
153 +
  chain-id="11155111"
154 +
  primary="#4F46E5"
155 +
  background="#1F2937"
156 +
  border-radius="8px">
157 +
</connect-wallet>
158 +
```
159 +
160 +
### `contract-call`
161 +
162 +
A custom HTML element for interacting with Ethereum smart contracts. Supports both read-only (view/pure) and write operations through wallet integration.
163 +
164 +
**Attributes:**
165 +
- `contract-address` (required) - The Ethereum contract address
166 +
- `method-name` (required) - The contract method to call
167 +
- `method-args` - JSON array of method arguments (default: `[]`)
168 +
- `abi` - JSON string of the contract ABI
169 +
- `abi-url` - URL to fetch the contract ABI from
170 +
- `chain-id` - Ethereum chain ID in decimal or hex format (default: `"1"` for mainnet)
171 +
- `button-text` - Text displayed on the call button (default: `"Call Contract"`)
172 +
- `background` - Background color (default: `"#232323"`)
173 +
- `foreground` - Text color (default: `"#ffffff"`)
174 +
- `primary` - Primary button color (default: `"#5F8787"`)
175 +
- `secondary` - Secondary/hover color (default: `"#6F9797"`)
176 +
- `border-radius` - Border radius for UI elements (default: `"4px"`)
177 +
- `error-color` - Color for error messages (default: `"#E78A53"`)
178 +
- `success-color` - Color for success messages (default: `"#5F8787"`)
179 +
180 +
**Events:**
181 +
- `abi-loaded` - Fired when ABI is successfully loaded from URL
182 +
- `abi-error` - Fired when ABI loading fails
183 +
- `contract-call-success` - Fired when contract call succeeds
184 +
- `contract-call-error` - Fired when contract call fails
185 +
186 +
**Example:**
187 +
```html
188 +
<contract-call
189 +
  contract-address="0x8C9EC9c13812C7F9F26AB934d4bF36206240dDA8"
190 +
  chain-id="11155111"
191 +
  method-name="increment"
192 +
  abi='[{"inputs":[],"name":"increment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"number","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newNumber","type":"uint256"}],"name":"setNumber","outputs":[],"stateMutability":"nonpayable","type":"function"}]'
193 +
  button-text="Increment">
194 +
</contract-call>
195 +
```
196 +
197 +
### `contract-read`
198 +
199 +
A custom HTML element for reading state from Ethereum smart contracts. Automatically loads and displays read-only contract state on mount. Supports both wallet integration and direct RPC calls.
200 +
201 +
**Attributes:**
202 +
- `contract-address` (required) - The Ethereum contract address
203 +
- `method-name` (required) - The contract method to call
204 +
- `method-args` - JSON array of method arguments (default: `[]`)
205 +
- `abi` - JSON string of the contract ABI
206 +
- `abi-url` - URL to fetch the contract ABI from
207 +
- `rpc-url` - RPC URL for direct calls (used when wallet is not available)
208 +
- `chain-id` - Ethereum chain ID in decimal or hex format (default: `"1"` for mainnet)
209 +
- `background` - Background color (default: `"#232323"`)
210 +
- `foreground` - Text color (default: `"#ffffff"`)
211 +
- `primary` - Primary color (default: `"#5F8787"`)
212 +
- `border-radius` - Border radius for UI elements (default: `"4px"`)
213 +
- `error-color` - Color for error messages (default: `"#E78A53"`)
214 +
- `success-color` - Color for success messages (default: `"#5F8787"`)
215 +
216 +
**Events:**
217 +
- `abi-loaded` - Fired when ABI is successfully loaded from URL
218 +
- `abi-error` - Fired when ABI loading fails
219 +
- `contract-read-success` - Fired when contract read succeeds
220 +
- `contract-read-error` - Fired when contract read fails
221 +
222 +
**Example:**
223 +
```html
224 +
<contract-read
225 +
  contract-address="0x8C9EC9c13812C7F9F26AB934d4bF36206240dDA8"
226 +
  chain-id="11155111"
227 +
  method-name="number"
228 +
  rpc-url="https://sepolia.drpc.org"
229 +
  abi='[{"inputs":[],"name":"increment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"number","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newNumber","type":"uint256"}],"name":"setNumber","outputs":[],"stateMutability":"nonpayable","type":"function"}]'
230 +
  button-text="Current Count">
231 +
</contract-read>
232 +
```
233 +
15 234
## Local Development Setup
16 235
17 236
1. Clone and install dependencies with [Bun](https://bun.sh)
32 251
33 252
3. Build
34 253
35 -
After editing components and testing them in the dev server you can run the `build` command to generate the CLI from `src/index.ts` that will create a `dist` folder. This enables users to run something like `npx norns-ui@latest init` to setup a project and add components, similar to shadcn/ui.
36 -
37 -
## Roadmap
38 -
39 -
Still figuring this out, suggestions and examples welcome!
40 -
41 -
**CLI**
42 -
43 -
- [x] Implement `norns.json` initialization
44 -
- [x] Improve styles and UX of commands and help menus
45 -
- [x] Include utility files like types in initialization and `norns.json`
254 +
```bash
255 +
bun run build
256 +
```
46 257
47 -
**Components**
258 +
After editing components and testing them in the dev server you can run the `build` command to generate the CLI from `src/index.ts` that will create a `dist` folder. This enables users to run something like `npx norns-ui@latest init` to setup a project and add components, similar to shadcn/ui.
48 259
49 -
- [x] Connect Wallet
50 -
- [x] Contract Call
51 -
- [x] Contract State (similar to contract call but auto loads the state)
52 -
- [x] Framework compatability
53 -
  - [x] React
54 -
  - [x] Svelte
55 -
  - [x] Vue
56 -
- [x] General types through JSDoc?
57 -
- [x] Add tailwindcss class/className prop
260 +
Examples can be found under the `examples` directory, containing pre-installed components for multiple frameworks.
58 261
59 262
## Contributing
60 263