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

@annoyingmouse/wc-risk-matrix

v1.0.2

Published

This web component creates a highly configurable, accessible risk matrix.

Readme

This web component creates a highly configurable, accessible risk matrix, with likelihood on the vertical axis and impact on the horizontal axis.

Published on webcomponents.org

Demo

<wc-risk-matrix likelihood="3" impact="4"></wc-risk-matrix>

See index.html in the repository for a fuller live demo, including a non-square matrix, custom colours, and an externally-restyled example.

Installation

<link rel="stylesheet" href="https://unpkg.com/@annoyingmouse/[email protected]/wc-risk-matrix.css">
<script type="module" src="https://unpkg.com/@annoyingmouse/[email protected]/wc-risk-matrix.js"></script>

Or, minified:

<script type="module" src="https://unpkg.com/@annoyingmouse/[email protected]/dist/wc-risk-matrix.min.js"></script>

Or from npm:

npm install @annoyingmouse/wc-risk-matrix

Usage

<link rel="stylesheet" href="wc-risk-matrix.css">

<wc-risk-matrix
  likelihood="3"
  impact="4"
  likelihood-steps="5"
  impact-steps="5"
></wc-risk-matrix>

<script type="module" src="wc-risk-matrix.js"></script>

Configuration

The matrix's dimensions, current selection and labels can all be changed using attributes, or the equivalent JavaScript properties.

| Attribute | Property | Type | Default | Description | | ------------------- | ------------------ | -------------------- | ------------- | ----------------------------------------------------- | | likelihood | likelihood | integer 1–steps, or null | null | Currently selected likelihood | | impact | impact | integer 1–steps, or null | null | Currently selected impact | | likelihood-steps | likelihoodSteps | positive integer | 5 | Number of likelihood levels (rows) | | impact-steps | impactSteps | positive integer | 5 | Number of impact levels (columns) | | likelihood-label | likelihoodLabel | string | Likelihood | Vertical axis label | | impact-label | impactLabel | string | Impact | Horizontal axis label | | colours | colours | JSON string / array | generated | Score-to-colour mapping, see Colours |

Both likelihood-steps and impact-steps are independent, so the matrix does not need to be square:

<wc-risk-matrix likelihood-steps="3" impact-steps="5"></wc-risk-matrix>

Validation

Attributes and properties are validated differently, deliberately:

  • Attributes are forgiving. A missing or out-of-range likelihood/impact reads back as null (no selection) rather than breaking rendering, and invalid likelihood-steps/impact-steps fall back to the default of 5.
  • Properties, being an explicit call from your own code, are strict. Setting matrix.likelihood = 99 on a 5-step matrix throws a RangeError, and setting matrix.likelihoodSteps = 0 throws too.

Score

matrix.score

A read-only, derived property equal to likelihood * impact. It is null whenever either value is unset. There is no score attribute — the score is always calculated, never stored.

Value

matrix.value

Returns null if there is no complete selection, otherwise an aggregate object:

{
  likelihood: 3,
  impact: 4,
  score: 12,
  colour: '#fce5cd'
}

It can also be assigned as a convenience for setting both axes at once:

matrix.value = { likelihood: 3, impact: 4 }
matrix.value = null // clears the selection

Colours

Each score maps to a colour using:

colours[score - 1]

The array needs likelihoodSteps * impactSteps entries (one per possible score). Several adjacent scores commonly share a colour:

matrix.colours = [
  '#d9ead3', '#d9ead3', '#d9ead3', '#d9ead3',
  '#fff2cc', '#fff2cc', '#fff2cc', '#fff2cc', '#fff2cc',
  '#fce5cd', '#fce5cd', '#fce5cd', '#fce5cd', '#fce5cd',
  '#f4cccc', '#f4cccc', '#f4cccc', '#f4cccc', '#f4cccc',
  '#e06666', '#e06666', '#e06666', '#e06666', '#e06666', '#e06666'
]

Colours can also be supplied declaratively as a JSON attribute:

<wc-risk-matrix colours='["#d9ead3","#fff2cc","#fce5cd","#f4cccc"]'></wc-risk-matrix>

Rich values like arrays are more naturally supplied through the JavaScript property; the attribute is a convenience for static, declarative markup.

Colours must be valid 3- or 6-digit hex CSS colours (#fff or #ffffff). Setting the colours property to something invalid throws a TypeError. An invalid colours attribute (bad JSON, non-array, or invalid colours) is handled gracefully: a warning is logged to the console and generated default colours are used instead, so a typo in markup never breaks the matrix.

If no colours are supplied, defaults are generated for any matrix size by bucketing each score's percentage of the maximum possible score (likelihoodSteps * impactSteps) into a five-colour progression from green through yellow, amber and red to a stronger red.

Events

Activating a cell (by click, or keyboard Enter/Space, since cells are real <button> elements) updates the selection and fires:

matrix.addEventListener('risk-select', event => {
  console.log(event.detail)
  // { likelihood: 3, impact: 4, score: 12, colour: '#fce5cd' }
})

risk-select is dispatched with { bubbles: true, composed: true }, so it can also be caught via delegation higher up the document. It fires only on genuine user activation — setting likelihood, impact, value, or the corresponding attributes from your own code never dispatches it.

CSS classes and data attributes

Because the component renders in light DOM, everything below is a stable target for ordinary CSS, with no ::part or shadow-DOM API needed:

wc-risk-matrix .risk-matrix               /* the <table> */
wc-risk-matrix .risk-matrix__row          /* each <tr> */
wc-risk-matrix .risk-matrix__cell         /* each <td> */
wc-risk-matrix .risk-matrix__button       /* each cell's <button> */
wc-risk-matrix .risk-matrix__button--selected
wc-risk-matrix .risk-matrix__likelihood   /* row <th scope="row"> */
wc-risk-matrix .risk-matrix__impact       /* column <th scope="col"> */
wc-risk-matrix .risk-matrix__corner       /* empty corner <th> cells */
wc-risk-matrix .risk-matrix__label        /* the "Likelihood"/"Impact" axis headings */

Every button also carries data-* attributes for styling or inspection:

wc-risk-matrix [data-score='25'] { }
wc-risk-matrix [data-likelihood='5'] { }
wc-risk-matrix [data-impact='4'] { }

CSS custom properties

--risk-colour           /* set per-button from the calculated cell colour */
--risk-border-colour
--risk-border-radius
--risk-text-colour
--risk-focus-colour
--risk-selected-colour

wc-risk-matrix.css sets each button's background from --risk-colour rather than an inline background declaration, so consumers stay free to restyle the whole component:

wc-risk-matrix .risk-matrix__button {
  border-radius: 50%;
}

Accessibility

  • The matrix is a real <table>, with <th scope="col"> for impact headings and <th scope="row"> for likelihood headings.
  • Each cell is a real <button type="button">, so keyboard activation (Enter/Space), focus and tab order all come from the browser, not bespoke JavaScript.
  • Risk is never communicated by colour alone: every button displays its numeric score and has an aria-label such as "Likelihood 3, impact 4, risk score 12".
  • The selected cell exposes aria-pressed="true"; every other cell exposes aria-pressed="false".
  • Focus indication is left to the browser's default (or your own CSS via --risk-focus-colour/:focus-visible), never suppressed outright.

Light DOM

<wc-risk-matrix> deliberately does not use Shadow DOM. All rendered markup is ordinary light-DOM content, so it can be styled with plain page CSS, inspected with normal devtools, and integrated into an existing stylesheet without ::part.

Form association

<wc-risk-matrix> is a form-associated custom element (static formAssociated = true), so it can participate in a <form> like a native control:

<form>
  <wc-risk-matrix name="risk" likelihood="3" impact="4"></wc-risk-matrix>
</form>

The submitted value is the numeric score as a string (e.g. "12"), not a likelihood,impact pair or a FormData-style multi-field submission. A single risk score is the value most consumers actually need on submission; if you need the individual likelihood/impact values server-side too, read matrix.value client-side and submit them as separate hidden fields.

Browser support

Targets current evergreen browsers (native Custom Elements v1, ElementInternals/form-associated custom elements). No polyfills are included.

Examples

<link rel="stylesheet" href="wc-risk-matrix.css">

<wc-risk-matrix
  id="risk"
  likelihood="3"
  impact="4"
  likelihood-steps="5"
  impact-steps="5"
></wc-risk-matrix>

<script type="module" src="wc-risk-matrix.js"></script>

<script>
  const risk = document.querySelector('#risk')

  risk.colours = [
    '#d9ead3', '#d9ead3', '#d9ead3', '#d9ead3',
    '#fff2cc', '#fff2cc', '#fff2cc', '#fff2cc', '#fff2cc',
    '#fce5cd', '#fce5cd', '#fce5cd', '#fce5cd', '#fce5cd',
    '#f4cccc', '#f4cccc', '#f4cccc', '#f4cccc', '#f4cccc',
    '#e06666', '#e06666', '#e06666', '#e06666', '#e06666', '#e06666'
  ]

  risk.addEventListener('risk-select', event => {
    console.log(event.detail)
  })
</script>

See index.html for a fuller live demo, including a non-square matrix and an externally-restyled example.

License

MIT