npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@nectary/labs

v2.5.41

Published

Welcome to Nectary Labs! This is the experimental playground for new components, patterns, and features that are being evaluated for inclusion in the main Nectary design system.

Readme

Nectary Labs

Welcome to Nectary Labs! This is the experimental playground for new components, patterns, and features that are being evaluated for inclusion in the main Nectary design system.

🎯 What is Nectary Labs?

Nectary Labs is a shared component library where any team can contribute their own experimental components. When a component is requested or used by multiple teams, it becomes a candidate for promotion to the main Nectary design system by the official Nectary team.

Think of it as an incubator where teams can share components with each other, and the most useful ones graduate to become officially supported in the main Nectary repository based on cross-team adoption.

🚀 Getting Started

Development Setup

  1. Clone the repository

    git clone <repository-url>
    cd nectary
  2. Install dependencies

    pnpm install
  3. Start the docs locally

    pnpm start
  4. Create documentation page for testing

    Create a documentation page in docs/latest/src/pages/labComponents/YourComponent/ to display and manually test your component. This is essential for development and validation.

    // docs/latest/src/pages/labComponents/YourComponent/examples/Basic.tsx
    import '@nectary/labs/your-component'
    
    export const BasicExample = () => (
      <sinch-labs-your-component 
        text="Hello World"
        disabled={false}
      />
    )

📝 Creating a New Component

1. Component Structure

Create a new directory following the naming convention:

mkdir my-new-component
cd my-new-component

2. Create Documentation Page

First, create a documentation page in docs/latest/src/pages/labComponents/MyComponent/ to display and manually test your component during development:

// docs/latest/src/pages/labComponents/MyComponent/examples/Basic.tsx
import '@nectary/labs/my-new-component'

export const BasicExample = () => (
  <sinch-labs-my-new-component 
    text="Hello World"
    disabled={false}
  />
)

3. Create the TypeScript File (index.ts)

import { defineCustomElement, NectaryElement } from '../utils'
import templateHTML from './template.html'
import type React from 'react'

const template = document.createElement('template')
template.innerHTML = templateHTML

export class MyNewComponent extends NectaryElement {
  // Private fields for DOM elements
  #button: HTMLButtonElement
  #controller: AbortController | null = null

  constructor() {
    super()

    const shadowRoot = this.attachShadow()
    shadowRoot.appendChild(template.content.cloneNode(true))

    // Query DOM elements
    this.#button = shadowRoot.querySelector('#button')!
  }

  connectedCallback() {
    super.connectedCallback()

    this.#controller = new AbortController()
    const { signal } = this.#controller

    // Add event listeners
    this.#button.addEventListener('click', this.#onClick, { signal })

    this.#updateUI()
  }

  disconnectedCallback() {
    super.disconnectedCallback()
    this.#controller?.abort()
    this.#controller = null
  }

  static get observedAttributes() {
    return ['disabled', 'text']
  }

  attributeChangedCallback(name: string, oldVal: string | null, newVal: string | null) {
    if (oldVal === newVal) return

    switch (name) {
      case 'disabled':
      case 'text':
        this.#updateUI()
        break
    }
  }

  // Properties with getters/setters
  get disabled(): boolean {
    return this.hasAttribute('disabled')
  }

  set disabled(value: boolean) {
    if (value) {
      this.setAttribute('disabled', '')
    } else {
      this.removeAttribute('disabled')
    }
  }

  get text(): string {
    return this.getAttribute('text') ?? ''
  }

  set text(value: string) {
    this.setAttribute('text', value)
  }

  #updateUI() {
    if (!this.isDomConnected) return

    this.#button.disabled = this.disabled
    this.#button.textContent = this.text
  }

  #onClick = () => {
    this.dispatchEvent(new CustomEvent('-click'))
  }
}

defineCustomElement('sinch-labs-my-new-component', MyNewComponent)

// TypeScript definitions
type Props = {
  disabled?: boolean
  text?: string
}

type ElementProps = Partial<{ [K in keyof Props]: Props[K] | string }>

declare global {
  interface HTMLElementTagNameMap {
    'sinch-labs-my-new-component': ElementProps & HTMLElement
  }
}

declare module 'react' {
  namespace JSX {
    interface IntrinsicElements {
      'sinch-labs-my-new-component': ElementProps &
        React.ClassAttributes<HTMLElement> &
        React.HTMLAttributes<HTMLElement>
    }
  }
}

4. Create the Template File (template.html)

<style>
:host {
  display: inline-block;
}

#button {
  padding: 8px 16px;
  border: 1px solid var(--sinch-sys-color-border-default);
  border-radius: 4px;
  background: var(--sinch-sys-color-surface-default);
  color: var(--sinch-sys-color-text-default);
  font: var(--sinch-sys-font-body-m);
  cursor: pointer;
}

#button:hover {
  background: var(--sinch-sys-color-surface-hover);
}

#button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
</style>

<button id="button" type="button">
  Default Text
</button>

🎨 Design Patterns

Use Primitive Props and Slots for Composition

Only use primitive types (string, number, boolean) for component properties to keep components as close to native HTML as possible. For complex data structures, prefer slots/children over array props for better composability:

// ❌ Avoid complex props
<my-component config={{theme: "dark", items: [1, 2, 3]}} />
<my-component items={[{title: "Item 1"}, {title: "Item 2"}]} />

// ✅ Use primitive props and slotted children
<my-component theme="dark" count="3">
  <my-item title="Item 1" />
  <my-item title="Item 2" />
</my-component>

Event Naming Convention

Use the - prefix for custom events:

// Dispatch custom events
this.dispatchEvent(new CustomEvent('-click'))
this.dispatchEvent(new CustomEvent('-change', { detail: newValue }))

Attribute Reflection

Always reflect important properties as attributes:

get disabled(): boolean {
  return this.hasAttribute('disabled')
}

set disabled(value: boolean) {
  if (value) {
    this.setAttribute('disabled', '')
  } else {
    this.removeAttribute('disabled')
  }
}

Use CSS Custom Properties

Leverage design tokens for consistent styling:

:host {
  color: var(--sinch-sys-color-text-default);
  font: var(--sinch-sys-font-body-m);
  background: var(--sinch-sys-color-surface-default);
}

🚢 Submission Guidelines

Commit Messages

Follow conventional commit format:

feat(labs): add new component for data visualization
fix(labs): resolve accessibility issue in phone preview
docs(labs): update contributing guide with new patterns

We use semantic-release for automated versioning and publishing. Your commit messages directly determine the version bump:

  • feat: triggers a minor version bump (e.g., 1.2.0 → 1.3.0)
  • fix: triggers a patch version bump (e.g., 1.2.0 → 1.2.1)
  • docs:, style:, refactor: etc. don't trigger a release
  • Breaking changes (with BREAKING CHANGE: in footer) trigger a major version bump (e.g., 1.2.0 → 2.0.0)

This means your commit message format is crucial for proper versioning and release notes generation.

Pull Request Process

  1. Create Feature Branch: git checkout -b feat/my-new-component
  2. Implement Component: Follow the patterns above
  3. Test Thoroughly: Run build, lint, and manual tests
  4. Update Documentation: Add usage examples
  5. Submit PR: Include clear description and testing notes

Code Review Criteria

  • Architecture: Follows Nectary Labs patterns
  • Performance: Efficient event handling and DOM updates
  • Accessibility: Proper ARIA attributes and keyboard support
  • Design: Consistent with design system tokens
  • Documentation: Clear examples and API documentation

🐛 Troubleshooting

Common Issues

TypeScript Conflicts: If you see "Subsequent property declarations must have the same type":

  • Remove any old compiled .d.ts files
  • Run npm run build to regenerate types
  • Restart TypeScript service in your editor

Import Errors: Ensure all child components are properly imported:

  • Check import paths are correct
  • Verify component registration
  • Import child components before parent components

Styling Issues:

  • Use :host for component root styles
  • Ensure CSS custom properties are defined
  • Check shadow DOM style encapsulation

💬 Getting Help

  • Check existing components in labs/ for patterns and examples
  • Review the main Nectary design system documentation
  • Ask questions in #nectary channels or discussions
  • Browse the Lab Components section for live examples

Ready to contribute? Start by exploring existing components in the repository, then follow the patterns above to create your own experimental component that could benefit teams across the organization!