A comprehensive React UI component library designed exclusively for the AddonBone browser extension framework with customizable theming and consistent design patterns
npm install addon-ui


Addon UI - A comprehensive UI component library designed for the Addon Bone framework.
This library provides a set of customizable React components with theming capabilities to build modern,
responsive user interfaces.
- 🎨 Customizable Theming: Easily customize the look and feel of components through theme configuration
- đź§© Rich Component Set: Includes buttons, forms, layouts, modals, and more
- 🔌 Addon Bone Integration: Seamless integration with the Addon Bone framework
- 📚 Storybook Documentation: Comprehensive component documentation with examples
- 🛠️ TypeScript Support: Full TypeScript support with type definitions
- Installation
- Components
- Basic Usage
- Integration
- Customization
- Using Extra Props
- Theming and style reuse
- Radix UI and third-party integrations
- Icons and sprite
- Extra props
- Contributing
``bash`
npm install addon-ui
`bash`
pnpm add addon-ui
`bash`
yarn add addon-ui
This library now ships with dedicated documentation files for each component in the docs/ directory. Start here:
- Accordion
- Avatar
- Button
- Checkbox
- Dialog
- Drawer
- Footer
- Header
- Highlight
- Icon
- IconButton
- List (covers List and ListItem)
- Modal
- Odometer (component + useOdometer hook)Tabs
- ScrollArea
- Select
- SvgSprite
- Switch
- Tabs (includes , TabsList, TabsTrigger, TabsContent)ViewportProvider
- Tag
- TextArea
- TextField
- Toast
- Tooltip
- Truncate
- TruncateList
- View
- ViewDrawer
- ViewModal
- Viewport ( + useViewport)
Notes:
- Each CSS variables table lists only component-scoped variables with exact fallback chains from the corresponding \*
.module.scss file.
- Where a component wraps a Radix UI primitive, the doc links to the official Radix docs and lists common props.
`jsx
import React from "react";
import {Button, ButtonColor, ButtonVariant, TextField, UIProvider} from "addon-ui";
function App() {
return (
);
}
export default App;
`
Addon UI is designed exclusively for the Addon Bone framework and does not have a standalone build as it's connected
as a plugin. This library is an integral part of the Addon Bone ecosystem for developing browser extensions with a
shared codebase.
Addon Bone is a framework for developing browser extensions with a common codebase. This means you can create multiple
extensions with the same functionality but with different designs, localizations, and feature sets depending on the
needs of each extension while maintaining access to a shared codebase.
`ts
// adnbn.config.ts
import {defineConfig} from "adnbn";
import ui from "addon-ui/plugin";
export default defineConfig({
plugins: [
ui({
themeDir: "./theme", // Directory for theme files
configName: "ui.config", // Name of config files
styleName: "ui.style", // Name of style files
mergeConfig: true, // Merge configs from different directories
mergeStyles: true, // Merge styles from different directories
splitChunks: true, // Enable automatic chunk splitting for components
}),
],
});
`
| Option | Type | Default | Description |
| :------------ | :------------------------------------------------- | :------------ | :----------------------------------------------------------------------------------------------------- |
| themeDir | string | "." | Directory path where plugin configuration and style files are located. |configName
| | string | "config.ui" | Name of the configuration file. |styleName
| | string | "style.ui" | Name of the SCSS style file. |mergeConfig
| | boolean | true | Whether to merge configuration files from different directories. |mergeStyles
| | boolean | true | Whether to merge style files from different directories. |splitChunks
| | boolean \| (name: string) => string \| undefined | true | Enables automatic chunk splitting. If a function is provided, it can be used to customize chunk names. |
#### Customizing Chunk Names
You can pass a callback function to splitChunks to customize the generated chunk names:
`tsui-${name}
ui({
splitChunks: name => {
if (name === "button") return "ui-core-button";
return ;`
},
});
The addon-ui configuration is designed to retrieve configuration from each extension separately, allowing for
different designs for different extensions without changing any code. You only need to modify the configuration, style
variables, and icons.
The plugin looks for configuration files in specific directories within your project. By default, it searches in the
following locations (in order of priority):
1. App-specific directory: src/apps/[app-name]/[app-src-dir]/[theme-dir]src/shared/[theme-dir]
2. Shared directory:
Where [theme-dir] is the directory specified in the themeDir option (defaults to the current directory).
The mergeConfig option (default: true) determines whether configurations from multiple directories should be merged.
When enabled, configurations from both app-specific and shared directories will be combined, with app-specific values
taking precedence in case of conflicts. If disabled, only the first configuration found will be used (with app-specific
having priority).
You can create these files to customize the UI components:
#### ui.config.ts
You can use the defineConfig helper which provides type checking:
`ts
// src/shared/theme/ui.config.ts
import {defineConfig} from "addon-ui/config";
import {ButtonColor, ButtonRadius, ButtonVariant, TextFieldRadius, TextFieldSize} from "addon-ui";
import CloseIcon from "./icons/close.svg?react";
export default defineConfig({
components: {
button: {
variant: ButtonVariant.Contained,
color: ButtonColor.Primary,
radius: ButtonRadius.Medium,
},
textField: {
size: TextFieldSize.Medium,
radius: TextFieldRadius.Small,
},
// ... other component configurations
},
icons: {
close: CloseIcon,
// Other custom icons
},
});
`
The example above shows how to use the TypeScript configuration with the Addon Bone framework.
The defineConfig helper provides type checking and autocompletion for your configuration.
You can import enum values from "addon-ui/config" to ensure type safety when configuring components.
The configuration can also include SVG icons imported directly from your project files.
#### ui.style.scss
Similar to configuration files, style files are also searched for in the same directories with the same priority order.
The mergeStyles option (default: true) works the same way as mergeConfig, allowing styles from multiple
directories to be combined when enabled.
`scss
// src/shared/theme/ui.style.scss
// Custom CSS variables and mixins for theming
@import "addon-ui/theme";
@include light {
// Base colors
--primary-color: #3f51b5;
--secondary-color: #f50057;
--accent-color: #4caf50;
// Text colors
--text-primary-color: #212121;
--text-secondary-color: #757575;
// Background colors
--bg-primary-color: #ffffff;
--bg-secondary-color: #f5f5f5;
// Font settings
--font-family: "Roboto", sans-serif;
--font-size: 14px;
--line-height: 1.5;
// Button specific variables
--button-font-family: var(--font-family);
--button-font-size: var(--font-size);
--button-height: 34px;
--button-border-radius: 10px;
// Button size variants
--button-height-sm: 24px;
--button-height-md: 44px;
--button-height-lg: 54px;
// Button radius variants
--button-border-radius-sm: 5px;
--button-border-radius-md: 12px;
--button-border-radius-lg: 15px;
}
@include dark {
// Base colors for dark theme
--primary-color: #7986cb;
--secondary-color: #ff4081;
--accent-color: #66bb6a;
// Text colors for dark theme
--text-primary-color: #ffffff;
--text-secondary-color: #b0bec5;
// Background colors for dark theme
--bg-primary-color: #121212;
--bg-secondary-color: #1e1e1e;
}
`
The addon-ui library allows for extensive customization to create different designs for different extensions without
changing code. This is particularly useful in the Addon Bone framework where you might need to maintain multiple browser
extensions with the same functionality but different visual appearances.
You can customize the theme globally by passing props to the UIProvider:
`jsx
import {UIProvider} from "addon-ui";
const customTheme = {
components: {
button: {
variant: "outlined",
color: "primary",
},
textField: {
radius: "medium",
},
},
icons: {
// Custom icons
},
// Specify the DOM element to set theme/view/browser attributes on
container: "#app-root",
};
function App() {
return
}
`
| Prop | Type | Default | Description |
| :----------- | :----------------------------- | :---------- | :-------------------------------------------------------- |
| components | ComponentsProps | {} | Component-specific configuration overrides. |icons
| | Icons | {} | Custom SVG icons registration. |extra
| | ExtraProps | {} | App-wide extra properties. |storage
| | ThemeStorageContract \| true | undefined | Persistence storage for theme settings. |container
| | string \| Element \| false | "html" | Target element for attributes. Set to false to disable. |view
| | string | undefined | Custom view identifier for specific styling. |
Extra Props is a powerful feature that allows you to extend component props with custom properties. This is particularly
useful when you need to add custom functionality or data to components across your application without modifying the
original component code.
#### What are Extra Props?
Extra Props provide a way to pass additional properties to components throughout your application using React Context.
This allows you to:
- Add application-specific properties to UI components
- Share common data across multiple components
- Extend the library's components with your own custom properties
#### How to Use Extra Props
1. Configure Extra Props in your theme configuration:
`ts
// src/shared/theme/ui.config.ts
import {defineConfig} from "addon-ui/config";
export default defineConfig({
components: {
// Component configurations
},
extra: {
// Your custom properties
appName: "My Awesome App",
version: "1.0.0",
features: {
darkMode: true,
analytics: false,
},
},
icons: {
// Icon configurations
},
});
`
2. Access Extra Props in your components using the useExtra hook:
`jsx
import {useExtra} from "addon-ui";
function AppHeader() {
const extra = useExtra();
return (
{extra.appName}
Version: {extra.version}
);
}
`
#### Example Use Case
A common use case for Extra Props is to add application-specific configuration to UI components. For example, you might
want to add custom analytics tracking to buttons:
`jsx
import {Button, useExtra} from "addon-ui";
function TrackableButton(props) {
const extra = useExtra();
const handleClick = e => {
// Use extra props for analytics
if (extra.features.analytics) {
trackButtonClick(props.trackingId);
}
// Call the original onClick handler
props.onClick?.(e);
};
return ;
}
`
#### Extending ExtraProps in TypeScript
To get proper type checking for your custom Extra Props, you can extend the ExtraProps interface:
`ts
// ui.d.ts or similar file
import "addon-ui";
declare module "addon-ui" {
interface ExtraProps {
appName: string;
version: string;
features: {
darkMode: boolean;
analytics: boolean;
};
// Add any other custom properties
}
}
`
With this type definition, TypeScript will provide proper type checking and autocompletion when using the useExtra
hook:
`tsx
import React from "react";
import {useExtra, Button} from "addon-ui";
const FeatureFlag: React.FC<{feature: keyof ExtraProps["features"]; children: React.ReactNode}> = ({
feature,
children,
}) => {
const extra = useExtra();
// TypeScript knows that extra.features exists and has the properties we defined
if (extra.features[feature]) {
return <>{children}>;
}
return null;
};
// Usage
function App() {
return (
---
Theming and style reuse
- Global theme tokens (colors, typography, spacing, transitions) live in your
ui.style.scss.
- Each component also exposes its own --component-* variables. See the CSS variables tables in the docs to know exactly what you can override.
- Theme Mixins: Use @import "addon-ui/theme"; to access @include light { ... } and @include dark { ... } mixins.
- Universal Targeting: These mixins are container-agnostic. They work correctly whether the theme attribute is on a parent element or directly on the component itself.
- Context-Aware:
- When used at the top level, they generate global selectors: [theme="dark"] { ... }.
- When used inside a component, they generate scoped selectors: [theme="dark"] .my-comp, .my-comp[theme="dark"] { ... }.Radix UI and third-party integrations
Several components are built on Radix primitives (Dialog, Checkbox, ScrollArea, Switch, Toast) or wrap third-party
tools (react-highlight-words, odometer). Each doc links to the official API and explains which props you can pass
through.
Icons and sprite
- Register icons in
ui.config.ts or via UIProvider’s icons prop. The Icon component pulls symbols from the
automatically mounted SvgSprite.
- Icons are lazily registered: a symbol is added only after an Icon with that name renders at least once.
- See docs/Icon.md and docs/SvgSprite.md for details and examples.Extra props (cross-cutting configuration)
Use the
extra field in ui.config.ts to supply app-wide values (feature flags, labels, analytics switches) and access
them at runtime with the useExtra() hook. You can augment the ExtraProps TypeScript interface by declaration merging
for full type safety.Contributing
- Keep canonical end-user documentation in the
docs/ directory. When adding or changing CSS variables in a component’s
*.module.scss`, update the corresponding doc table.