1. Semantic Token Name Approach

Here you are grouping semantic usage for a set of fixed props, this could be: “paragraph”, “heading”, “body”, “label”. You end up with a set of base classNames in which you define fixed font-family, font-size, letter-spacing and line-height PER semantic-name + semantic-size.

Then we have the last leaf of each semantic token, you need at least a default config which will define defaults for stuff like font-weight, font-style. But you can also create modifiers, which will define new values for these properties, like: /semibold or /semibold-italic as you need.

/*
  FIGMA TOKEN NAMING CONVENTION:
  typography/[semantic-name]-[semantic-size]/default
  typography/[semantic-name]-[semantic-size]/[modifier]
  
  EXAMPLES:
  typography/title-lg/default
  typography/title-lg/semibold
  typography/title-lg/semibold-italic
  typography/title-lg/bold
  typography/title-lg/bold-italic
  typography/body-18/bold
  typography/body-18/semibold
  typography/body-18-tight/bold
  typography/body-18-tight/semibold

  WRONG EXAMPLES:
  typography/title/lg-tighter-semibold
  typography/title/lg-wide-bold

  What does the [semantic-name] define?
  - Font Family (sans, serif, mono)
  - Font Letter Spacing
  
  What does the [semantic-size] define?
  - Font Size
  - Font Line Height in ratio form (example: 1.2)
  - Font Letter Spacing

  What does the [modifier] define?
  - Weight (normal, medium, semibold, bold)
  - Font Style (normal, italic)
*/

Then, in the code you will just create classes for the default modifier, you have utility classes like:

@utility text-title-1 {
  @apply text-3xl font-semibold leading-tighter tracking-tighter;
}

@utility text-title-2 {
  @apply text-2xl font-semibold leading-tighter tracking-tight;
}

@utility text-title-3 {
  @apply text-xl font-semibold leading-tighter tracking-normal;
}

@utility text-title-4 {
  @apply text-lg font-semibold leading-tight tracking-wide;
}

@utility text-title-5 {
  @apply text-base font-semibold leading-tight tracking-wider;
}

@utility text-title-6 {
  @apply text-sm font-semibold leading-tight tracking-widest;
}

And then, you can overwrite them with tailwind css classes by reading the [modifier] semantic names to identify the modification. For example, the token name typography/title-sm/italic maps to className="text-title-sm italic", but you can also do <em> inside the element. Same thing with typography/paragraph-sm/bold, you could do <strong>. And you could even set a diff weight for strong tags inside text-paragraph-sm like:

@utility text-paragraph-6 {
  @apply text-sm font-normal leading-tight tracking-widest [&>strong]:font-semibold;
}

Consider using font-size token based for sizing to prevent future updates to shift the whole scale.

@utility text-paragraph-14 {
  @apply text-sm font-normal leading-tight tracking-widest [&>strong]:font-semibold;
}

2. Token Approach. AKA Joyboy approach.

The first component of this approach is the font-family + font-size let’s call this fixture font-profile. This “font-profile” has the letter-spacing and line-height fixed. The second component of this approach is the font-weight + font-style. We can call this “font-flavor” this allows you to have a set of flavors per each set of profiles, where you can assume that each profile has the same consistent letter-spacing and line-height across all flavors.