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

@graphql-workbench/schema-explorer

v0.3.0

Published

A macOS Finder-style column view web component for exploring GraphQL schemas

Readme

Schema Explorer

<gwb-schema-explorer> is a framework-agnostic web component for exploring GraphQL schemas in a macOS Finder-style column view. It supports SDL and introspection inputs, global search, semantic schema diffs, directives, deprecations, canonical navigation paths, keyboard navigation, and light/dark theming.

Install

npm install @graphql-workbench/schema-explorer graphql @preact/signals-core

graphql and @preact/signals-core are peer dependencies. Lit is installed as a normal runtime dependency.

Module usage

<gwb-schema-explorer id="explorer"></gwb-schema-explorer>

<script type="module">
  import '@graphql-workbench/schema-explorer';

  const explorer = document.querySelector('#explorer');
  explorer.schema = `
    type Query {
      user(id: ID!): User
    }

    type User {
      id: ID!
      name: String!
    }
  `;
</script>

The ES and CommonJS entries also export buildSchemaModel(), parseSDL(), parseIntrospection(), diffSchemaModels(), createSchemaExplorerStore(), SchemaExplorer, and the public TypeScript model, diff, selection, store, input, and event-detail types. CommonJS is intended for browser-capable, ESM-aware bundlers; importing the component requires a DOM. For Node, SSR setup, or a coordinator that needs only semantic state, import createSchemaExplorerStore() and parseSchemaExplorerStoreSnapshot() from @graphql-workbench/schema-explorer/store. That DOM-free subpath has its own ES, CommonJS, and declaration entries and does not register a custom element.

Signal store

createSchemaExplorerStore() exposes reusable semantic state without including column, focus, scrolling, search-presentation, or copy UI state. Writable signals hold schema inputs and preferences. Readonly signals expose resolved models, parse errors, diffs, and the validated selection.

import { createSchemaExplorerStore } from '@graphql-workbench/schema-explorer';

const store = createSchemaExplorerStore();
store.setSchemaInput({
  kind: 'raw',
  format: 'sdl',
  value: 'type Query { user: User } type User { id: ID! }',
});

const unsubscribe = store.events.subscribe('selection-change', ({ path, kind }) => {
  console.log(path, kind);
});

store.select('field:Query.user');
console.log(store.model.value, store.selectionPath.value, store.diffChanges.value);

unsubscribe();
store.dispose();

Current and baseline inputs use the same precedence as the component. The setSchemaInput() and setBaselineSchemaInput() actions atomically replace all input sources; consumers that need fallback behavior can write the individual signals. Selection changes emit typed events even when input changes invalidate or restore the selection. The include-deprecated-change preference event is action-only, so direct preference writes do not echo. Pass { emitEvents: false } to an action when applying an already-observed change. A coordinator may supply a shared writable theme signal through { theme }.

Use store.snapshot() for persistence and store.restore(value) to restore a snapshot. Snapshots are versioned, detached, deeply frozen, and JSON-serializable. They include all current and baseline inputs, the selection path, and durable preferences, but omit derived models, parse errors, diffs, and presentation state. Restoration validates the complete value before changing the store and does not emit user-action events. parseSchemaExplorerStoreSnapshot(value) performs the same validation without mutating a store, allowing a coordinator to validate all slices before restoring any of them.

Assign the same store to one or more components to synchronize their schema, preferences, diff, and semantic selection:

const store = createSchemaExplorerStore();
document.querySelector('#primary').store = store;
document.querySelector('#secondary').store = store;
store.schema.value = 'type Query { hello: String }';

The existing component properties remain available and delegate to the active store. When no store is supplied, the component owns a private one. Component interactions and navigateTo() continue to emit the existing DOM events; changes made directly through the store update every bound view without echoing DOM events. Disconnecting a view never disposes an injected store. Clearing or replacing an injected store preserves its durable inputs, preferences, and selection in a fresh private fallback. The consumer that created an injected store calls dispose() after its last view is finished; a view never disposes a borrowed store. The coordinator package @graphql-workbench/graphql-workbench-store can own this slice alongside an execution slice. Schema selection remains navigation state and never changes the consumer's query editor.

Inputs

The current schema uses this precedence order:

  1. schemaModel: an immutable model returned by a parser or buildSchemaModel()
  2. introspection: a bare introspection result or its { data } HTTP envelope
  3. schema with format="sdl" or format="introspection"

Set the parallel baselineSchemaModel, baselineIntrospection, baselineSchema, and baselineFormat inputs to compare a previous schema with the current schema. Clearing every baseline input returns to ordinary exploration.

import { parseSDL } from '@graphql-workbench/schema-explorer';

explorer.schemaModel = parseSDL(currentSDL);
explorer.baselineSchema = previousSDL;

Model default values are GraphQL literals. SDL parsing preserves the declared literal, and introspection parsing preserves its supplied default-value text, including object and list defaults for custom scalars. A programmatic schema default that cannot be rendered and has no source literal appears as null without invalidating the schema.

explorer.diffChanges exposes the immutable semantic result. Changes are classified as breaking, dangerous, or additive and can be opened from the built-in filtered change list. If the baseline cannot be parsed, its comparison error appears above the current schema; the current schema remains navigable. Correct the baseline to restore the diff summary, or clear it to return to ordinary exploration.

Selection and events

selectionPath is a reflected, serializable path such as type:User, field:Query.user, or argument:Query.user.id. Use await explorer.navigateTo(path) to reveal and focus a destination.

The component emits bubbling, composed events:

  • gwb-selection-change with { path, kind }
  • gwb-selection-path-error with { path, reason }
  • gwb-include-deprecated-change with { includeDeprecated }

Search, deprecation filtering, copy actions, and schema-change navigation are built into the component UI.

Themes and layout

Set theme to auto, light, or dark, and view-mode to multi-column or single-column.

gwb-schema-explorer {
  --gwb-se-height: 600px;
  --gwb-se-column-width: 280px;
  --gwb-se-font-family: Inter, sans-serif;
  --gwb-se-font-size: 14px;
  --gwb-se-selected-bg: #0058d0;
}

All supported color, typography, layout tokens, and ::part() names are inventoried in the project guidance. The default palette meets WCAG AA contrast requirements; custom themes remain the consumer's responsibility.

Standalone browser bundle

The self-contained UMD file bundles Lit and GraphQL for direct classic-script use:

<script src="schema-explorer.umd.js"></script>
<gwb-schema-explorer id="explorer"></gwb-schema-explorer>
<script>
  explorer.schemaModel = SchemaExplorer.parseSDL('type Query { hello: String }');
</script>

The SchemaExplorer global exposes the component, createSchemaExplorerStore(), parseSDL(), parseIntrospection(), and diffSchemaModels(). It intentionally omits buildSchemaModel(); consumers that already own a GraphQLSchema should use a module entry so both sides share the same GraphQL runtime.

See MIGRATING.md for breaking changes and CHANGELOG.md for release notes.

Development

npm ci
npx playwright install chromium firefox webkit
npm run check --workspace=@graphql-workbench/schema-explorer

Run these commands from the monorepo root.

The unified check runs formatting, linting, TypeScript, Vitest, packed-package and bundle validation, plus Playwright in Chromium, Firefox, and WebKit. Manual assistive-technology checks remain in the release checklist.