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

@arbetsformedlingen/yrkesvaljaren

v2.0.12

Published

Monorepo för Arbetsförmedlingens väljarkomponenter.

Readme

Yrkesväljaren webbkomponent

En robust och intelligent sökkomponent för svenska yrken, designad för hög prestanda och tillförlitlighet. Den integrerar yrken från Arbetsförmedlingens taxonomi i valfri webbapplikation.


Beskrivning

  • Enkelt hitta rätt yrke för användaren Sökalgoritmen prioriterar exakta träffar, prefix, flerdelade direktträffar och innehåller-träffar. Om inga direktträffar finns kan upp till tre fuzzy-träffar visas. Viktdata används som sekundär sortering.
  • Hög prestanda: Sökningen sker lokalt i webbläsaren mot inläst yrkesdata. Komponenten gör inga sökanrop till Taxonomy API.
  • Flexibel datahantering: Versionerat npm-datapaket (rekommenderas), automatiskt uppdaterad data eller en egen URL.

Installation

Installera komponenten och datapaketet:

npm install @arbetsformedlingen/yrkesvaljaren @arbetsformedlingen/yrkesvaljaren-data@31

Datapaketets majorversion är taxonomiversionen: 31.x.y innehåller taxonomi v31. Med ^31.0.0 i package.json får du rättningar av v31-datan men byter aldrig taxonomiversion av misstag. Installera nästa majorversion när du vill byta taxonomiversion.

Datan registreras med registerTaxonomy(...) innan komponenten används. Se Angular eller HTML och andra ramverk.

Utan registrerad data hämtar komponenten den senaste publicerade yrkesdatan från CDN. af-taxonomy-url är ett avancerat alternativ om du vill peka komponenten mot en egenhostad datafil.

Användning i Angular

De flesta som använder Yrkesväljaren bygger i Angular. Komponenten är en vanlig webbkomponent, så den fungerar i standalone-komponenter med eller utan zone.js.

Registrera datan och webbkomponenterna i main.ts innan appen startar. Taxonomidatan är cirka 2 MB. Importera den dynamiskt, så hamnar den i en egen chunk. Med en statisk import hamnar den i main-bundlen och ng build fastnar på Angulars standardbudget (1 MB).

// src/main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { defineCustomElements as defineYv } from '@arbetsformedlingen/yrkesvaljaren/loader';
import { registerTaxonomy } from '@arbetsformedlingen/yrkesvaljaren';
import { appConfig } from './app/app.config';
import { App } from './app/app';

async function main() {
  const { metadata, taxonomyData } = await import('@arbetsformedlingen/yrkesvaljaren-data');
  registerTaxonomy({ data: taxonomyData, metadata });
  defineYv(window);
  await bootstrapApplication(App, appConfig);
}
main().catch((err) => console.error(err));

Använd sedan komponenten i en standalone-komponent med CUSTOM_ELEMENTS_SCHEMA och lyssna på eventet i templaten:

// src/app/job-picker.component.ts
import { Component, CUSTOM_ELEMENTS_SCHEMA, signal } from '@angular/core';
import type { JobSelectionItem } from '@arbetsformedlingen/yrkesvaljaren';

@Component({
  selector: 'app-job-picker',
  standalone: true,
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `
    <digi-service-job-selector af-label="Välj yrke" (afJobSelected)="onJobSelected($event)"></digi-service-job-selector>
    <p>Valt yrke: {{ selected()[0]?.preferred_label ?? 'inget' }}</p>
  `,
})
export class JobPickerComponent {
  readonly selected = signal<JobSelectionItem[]>([]);

  onJobSelected(event: Event): void {
    this.selected.set((event as CustomEvent<JobSelectionItem[] | null>).detail ?? []);
  }
}

Uppdatera vyn via signals (eller ChangeDetectorRef) när ni sätter värden efter en await. Annars uppdateras inte vyn i zoneless-appar.

Kompletta exempel:

Användning i HTML och andra ramverk

För att snabbt komma igång, här är ett komplett HTML-exempel som visar hur du inkluderar och använder Yrkesväljaren:

<!DOCTYPE html>
<html lang="sv">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Yrkesväljaren exempel</title>
</head>
<body>

  <h1>Yrkesväljaren exempel</h1>

<!-- Komponenten -->
<digi-service-job-selector af-label="Välj yrke"></digi-service-job-selector>
<script type="module">

// Imports (sökväg beror på ditt byggverktyg)
import { defineCustomElements as defineYrkesvaljaren } from "@arbetsformedlingen/yrkesvaljaren/loader";
defineYrkesvaljaren(window);
document.querySelector("digi-service-job-selector")
.addEventListener("afJobSelected", (e) => {
console.log("Valt yrke:", e.detail);
});
</script>

</body>
</html>

Utan Angular: registrera datapaketets data innan komponenten används:

import { registerTaxonomy } from '@arbetsformedlingen/yrkesvaljaren';
import { taxonomyData, metadata } from '@arbetsformedlingen/yrkesvaljaren-data';

registerTaxonomy({ data: taxonomyData, metadata });

React: koppla komponentens event med addEventListener via en ref i en useEffect. Det fungerar i alla React-versioner; en onAfJobSelected-prop fungerar inte i React 18.

Vite

Yrkesväljaren använder en Stencil-loader som hämtar komponenternas entry-filer dynamiskt. I Vite ska loader-paketet därför undantas från dependency optimizer, annars kan Vite flytta loadern till .vite/deps och de dynamiska importerna får fel sökväg.

// vite.config.js
export default {
  optimizeDeps: {
    exclude: [
      '@arbetsformedlingen/yrkesvaljaren/loader',
    ],
  },
};

Designsystem-kompatibilitet

Yrkesväljaren är uppbyggd med designsystemets tokens, typografi, färger, fokusramar och ikoner och kommer att uppdateras automatiskt för dig som har designsystemet installerat. Den använder de förväntade attributen för att styla etikett, felmeddelande osv, men har inga komponentberoenden till designsystemet. För den som inte har designsystemet installerat används inbyggda fallbacks för att bibehålla utseendet.

Attribut

| Attribut | Beskrivning | Typ | Standardvärde | |:---|:---|:---|:---| | af-label | Etikettext som visas ovanför sökfältet. | string | 'Välj yrke' | | disabled | Om satt till true, kan väljaren inte användas med mus eller tangentbord. | boolean | false | | af-label-description| En valfri beskrivningstext som visas under etiketten. | string | undefined | | af-placeholder | Hjälptext som visas inuti sökfältet. Denna är ett bra stöd för de med kognitiv funktionsvariation - vi rekommenderar att behålla denna text (den är osynlig för skärmläsare). | string | 'T.ex. målare, florist, kock' | | af-error-message | Ett anpassat felmeddelande som visas vid valideringsfel. | string | undefined | | af-enable-multiple | Om satt till true, tillåts val av flera yrken. | boolean | false | | af-history | Sparar användarval lokalt i webbläsarens Local Storage och visar historiken på samma domän. | boolean | true | | af-required | Om satt till true, måste användaren göra ett val för att fältet ska vara giltigt (obligatoriskt fält). | boolean | false | | af-manual-input | Om satt till true kan användaren ange ett yrke som fritext när det inte finns i listan. Om satt till false måste ett fördefinierat yrke väljas. | boolean | false | | af-size | Storleken på inputfältet. Möjliga värden: 'small', 'medium', 'large'. | string | 'medium' | | af-popular | Om satt till true visas sektionen "Populära sökningar" när historiken är tom. | boolean | true | | af-taxonomy-url | Fullständig, explicit URL till en egenhostad datafil. Utelämna attributet för att använda senaste data automatiskt. | string | undefined |

Riktlinjer och rekommendationer

Tre centrala inställningar styr användarupplevelsen och datakvaliteten i Yrkesväljaren:

Obligatorisk (af-required)

  • Hur man kan resonera: När af-required="true" måste användaren välja minst ett yrke för att fältet ska betraktas som giltigt. Komponenten fungerar som ett standardenligt Form-Associated Custom Element (FACE). Det innebär att webbläsaren automatiskt validerar fältet vid formulärinskick, förhindrar att formuläret skickas in om det är tomt, och integrerar med formulärets validity-status.
  • När det rekommenderas: I formulär och flöden där ett yrkesval är ett obligatoriskt steg i ett ärende (t.ex. inskrivning och aktivitetsrapportering).
  • När det bör undvikas: I öppna sök- eller filtreringsvyer där användaren ska kunna söka brett, filtrera på andra parametrar (t.ex. enbart ort/geografi) eller frivilligt specificera yrke.

Tillåt fritext (af-manual-input)

  • Hur man kan resonera: Avgör om användaren strikt måste välja ett strukturerat yrkesbegrepp ur Arbetsförmedlingens taxonomi (vilket garanterar Concept ID och SSYK-kod), eller om användaren även tillåts mata in egna fritextvärden som inte finns i taxonomin. Vid fritext visas valet "Använd '{inmatning}'" i listan som användaren aktivt väljer eller bekräftar med Enter.
  • När det rekommenderas:
    • Strikt taxonomi (af-manual-input="false" – standard & rekommenderas): När yrkesdatan ska användas för automatisk matchning, statistiska analyser, maskininlärning eller integration mot backend-system som förutsätter Concept ID. Detta säkerställer hög datakvalitet.
    • Fritext tillåten (af-manual-input="true"): I öppna fritextprofiler, fritextenkäter eller intresseanmälningar där det är viktigare att fånga upp vad användaren själv kallar sin roll än att få ett taxonomi-ID, eller där man inte vill blockera användare med ovanliga, nischade eller internationella titlar.

Tillåt historik (af-history)

  • Hur man kan resonera: Sparar gjorda val i webbläsarens localStorage per domän och enhet, och visar dem som "Tidigare val" när användaren fokuserar Yrkesväljaren. Det betyder att historiken kommer att visas på alla tjänster med yrkesväljare på arbetsformedlingen.se (så länge personen använder samma enhet, t.ex. sin mobil).
  • När det rekommenderas: På alla tjänster mot konsumenter.
  • När det bör undvikas: På delade publika terminaler eller kioskdatorer (t.ex. på Arbetsförmedlingens servicekontor) där personers tidigare sökningar inte ska sparas eller exponeras för efterföljande besökare på samma dator. I handläggartjänster är historiken sällan till hjälp, eftersom handläggare söker på många olika yrken.

Välj datakälla

Välj ett av följande sätt:

  1. Registrera ett versionerat datapaket med registerTaxonomy(...).
  2. Ange en fullständig URL med af-taxonomy-url för en egenhostad datafil.
  3. Utelämna båda för att använda senaste data automatiskt.

En angiven af-taxonomy-url är den valda datakällan. Om URL:en inte kan laddas går komponenten till felläge och skickar afJobDataLoadFailed.

Events

| Händelse | Beskrivning | |:---|:---| | afJobSelected | Skickas ut när användaren ändrar valet. event.detail innehåller JobSelectionItem[] som kan skickas tillbaka till setSelection(). | | afJobDataLoadFailed | Skickas när laddningen av yrkesdata misslyckas. | | afJobValidationChange | Skickas när komponenten kör validering efter att fältet har berörts. event.detail innehåller { isValid: boolean, errorType: 'required'|'invalidInput'|null }. |

Metoder

Yrkesväljaren exponerar några metoder för värdapplikationer som behöver styra komponenten från JavaScript. De vanligaste är setSelection(...) och setFocus(). Övriga metoder finns för formulärintegration och dynamisk dataladdning.

Primära metoder

| Metod | Returvärde | Beskrivning | |:---|:---|:---| | setSelection(input) | Promise<JobSelectionItem[]> | Sätter eller rensar ett programmatiskt val. Returnerar komponentens normaliserade val. | | setFocus() | Promise<void> | Flyttar fokus till sökfältet. Används när värdappen till exempel öppnar en modal eller vill fokusera fältet efter ett fel. |

Formulärvalidering

Yrkesväljaren är ett form-associated custom element. Det betyder att den kan delta i vanliga HTML-formulär ungefär som ett inbyggt inputfält. Metoderna nedan är till för värdapplikationer som behöver läsa eller trigga den valideringen manuellt.

| Metod | Returvärde | Beskrivning | |:---|:---|:---| | validate(forceTouch?) | Promise<boolean> | Kör Yrkesväljarens egen validering. Returnerar true om fältet är giltigt. Med forceTouch=true visas valideringsfel även om användaren inte hunnit interagera med fältet. | | checkValidity() | Promise<boolean> | Returnerar om komponenten är giltig enligt webbläsarens formulärvalidering. Visar inget felmeddelande i UI. | | reportValidity() | Promise<boolean> | Kör webbläsarens formulärvalidering och låter webbläsaren visa valideringsfeedback om fältet är ogiltigt. | | getValidity() | Promise<ValidityState> | Returnerar webbläsarens detaljerade giltighetsstatus, till exempel om värdet saknas eller om komponenten har satt ett eget fel. De flesta integrationer behöver bara validate() eller checkValidity(). | | getValidationMessage() | Promise<string> | Returnerar texten som webbläsaren skulle använda som valideringsmeddelande just nu. |

Dynamisk dataladdning

| Metod | Returvärde | Beskrivning | |:---|:---|:---| | updateData() | Promise<void> | Läser om data efter ett nytt anrop till registerTaxonomy(...). Behövs bara om värdappen byter taxonomidata efter att komponenten redan har renderats. |

Input och output - programmatisk värdesättning

Programmatisk input går endast genom setSelection(). Metoden accepterar:

  • en sträng
  • en array där alla värden är strängar
  • den rika JobSelectionItem[] som afJobSelected tidigare har returnerat

Output är alltid en rik JobSelectionItem[], både från metodens returvärde och från afJobSelected.detail.

type JobSelectionItem =
  | {
      type: 'job-title' | 'occupation-name';
      id: string;
      preferred_label: string;
      ssyk_code_2012?: string;
      related?: {
        type: 'occupation-name';
        id: string;
        preferred_label: string;
      };
    }
  | {
      type: 'manual-input';
      id: null;
      preferred_label: string;
    };

För vanliga formulär hämtas värdet lämpligen via new FormData(form). För applikationsstate sparar värdappen metodens returvärde eller afJobSelected.detail.

afJobSelected använder samma format som metoden returnerar. Output kan därför sparas av värdappen och senare skickas tillbaka utan konvertering:

yrkesvaljaren.addEventListener("afJobSelected", async (event) => {
  await annanYrkesvaljare.setSelection(event.detail);
});
  • Inget valt: await yrkesvaljaren.setSelection([])
  • Taxonomival in: await yrkesvaljaren.setSelection('jrjV_wcz_fxg')
  • Taxonomival ut: { type: 'job-title', id: 'jrjV_wcz_fxg', preferred_label: 'Sjuksköterska', ssyk_code_2012: '2221', related: { type: 'occupation-name', id: 'bXNH_MNX_dUR', preferred_label: 'Sjuksköterska, grundutbildad' } }
  • Fritext in: await yrkesvaljaren.setSelection('Pensionär') kräver af-manual-input="true"
  • Fritext ut: { type: 'manual-input', id: null, preferred_label: 'Pensionär' }

En sträng som matchar Concept ID-formatet tolkas alltid som ett taxonomi-id och verifieras mot det laddade YV-datasetet. Övriga strängar tolkas som fritext. Fritext kräver af-manual-input="true".

Komponenten gör inget anrop till Taxonomy API. För ett rikt taxonomiobjekt identifierar id yrket; YV returnerar aktuell metadata från det redan laddade datasetet. ssyk_code_2012 är SSYK 2012-koden när den finns i YV-datat. Komponenten returnerar inget fält som heter ssyk och returnerar inte SSYK-nivåns taxonomi-id.

Samma input-array får inte blanda strängar och objekt. Flera värden kräver af-enable-multiple="true"; metoden aktiverar aldrig flervalsläge automatiskt.

import { InvalidSelectionError } from '@arbetsformedlingen/yrkesvaljaren';

const yrkesvaljaren = document.querySelector('digi-service-job-selector');

try {
  const selection = await yrkesvaljaren.setSelection([
    'iW55_9hv_bNp',
    'Pensionär'
  ]);
  console.log('Valda yrken:', selection);
} catch (error) {
  if (error instanceof InvalidSelectionError) {
    console.error(error.code, error.invalidIds);
  }
}

Om inputen är ogiltig avvisas Promise-anropet med InvalidSelectionError. Senaste giltiga val behålls, ett tydligt fel skrivs med console.error, och Yrkesväljaren markeras som invalidInput via afJobValidationChange. setSelection() skickar inte afJobSelected; eventet representerar endast användarens val.

Rensa val (både singel- och flervalsläge)

För att programmatiskt rensa gjorda val, anropa setSelection([]):

const yrkesvaljaren = document.querySelector('digi-service-job-selector');
await yrkesvaljaren.setSelection([]);

Validering

Komponenten har ett inbyggt, autonomt valideringssystem.

Obligatoriskt fält

För att göra fältet obligatoriskt, använd af-required-attributet och ställ in af-manual-input på false.

<digi-service-job-selector
  af-label="Välj ett yrke (obligatoriskt)"
  af-required="true"
  af-manual-input="false"
></digi-service-job-selector>

När detta är inställt kommer komponenten att visa ett felmeddelande om användaren klickar i och sedan lämnar fältet utan att göra ett giltigt val. Om af-manual-input i stället är satt till true tillåts användaren att ange ett yrke manuellt via fritext.

Lyssna på valideringsstatus (afJobValidationChange)

För att i realtid veta om komponenten är giltig kan du lyssna på afJobValidationChange-händelsen.

const yrkesvaljarenElement = document.querySelector('digi-service-job-selector');

yrkesvaljarenElement.addEventListener('afJobValidationChange', (event) => {
  const { isValid, errorType } = event.detail;
  console.log(`Är komponenten giltig? ${isValid}`);
  if (!isValid) {
    console.log(`Typ av fel: ${errorType}`); // 'required' eller 'invalidInput'
  }
});

För att manuellt trigga en validering, till exempel vid ett formulär-submit, kan du anropa den publika metoden validate().

Formulärstöd (FACE)

Komponenten agerar som ett inbyggt HTML-formulärelement (Form-Associated Custom Element). Detta innebär att om komponenten ligger i ett <form> och har af-required="true" kommer webbläsaren automatiskt att stoppa inskick av formuläret om fältet är tomt. Det går även bra att hämta värdet via new FormData(form).

name följer HTML-standard och fungerar som på <input name="...">. Det är därför inte prefixat med af-. Värdet används som fältnamn och nyckel i FormData.

<form id="job-form">
  <digi-service-job-selector
    name="occupation"
    af-label="Välj yrke"
    af-required="true">
  </digi-service-job-selector>
</form>
const form = document.querySelector('#job-form');
const yrkesvaljarenElement = document.querySelector('digi-service-job-selector');

form.addEventListener('submit', async (e) => {
  e.preventDefault();
  const isComponentValid = await yrkesvaljarenElement.validate();

  if (isComponentValid) {
    const formData = new FormData(form);
    console.log(formData.get('occupation'));
    console.log('Formuläret är giltigt och kan skickas!');
    // Skicka formulär...
  } else {
    console.log('Formuläret är ogiltigt.');
  }
});