Skip to content

OakButton component#592

Open
weronika-szalas wants to merge 5 commits into
mainfrom
oak-button-component
Open

OakButton component#592
weronika-szalas wants to merge 5 commits into
mainfrom
oak-button-component

Conversation

@weronika-szalas
Copy link
Copy Markdown
Contributor

@weronika-szalas weronika-szalas commented Feb 18, 2026

Add your PR description below

  • created OakButton component as a proof of concept for Oak Components Standards doc and introduced colorScheme, size and variant API
  • marked relevant button components as deprecated
    • OakPrimaryButton
    • OakPrimaryInvertedButton
    • OakSecondaryButton
    • OakSmallPrimaryButton
    • OakSmallPrimaryInvertedButton
    • OakSmallSecondaryButton
    • OakTertiaryButton
    • OakTertiaryInvertedButton
  • replaced all occurrences of deprecated components with OakButton

Awaiting design decision

  • awaiting design decision regarding OakSmallTertiaryInvertedButton
    • OakSmallTertiaryInvertedButton differs by more than a size from OakTertiaryInvertedButton
    • awaiting decision whether we want to update small tertiary inverted button or keep its styling and perhaps make it a new variant of the OakButton
    • I didn't deprecate it yet in my PR as the decision hasn't been made yet

Link to the design doc

https://www.figma.com/design/YcWQMMhHPVVmc47cHHEEAl/Oak-Design-Kit?node-id=3459-11008&p=f&m=dev

A link to the component in the deployment preview

https://oak-components-storybook-git-oak-button-component.vercel.thenational.academy/?path=/docs/components-buttons-oakbutton--docs

Testing instructions

ACs

@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 18, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
oak-components-storybook Ready Ready Preview, Comment Feb 19, 2026 0:13am

Request Review

iconSize: sizeConfig.iconSize,
};

switch (variant) {
Copy link
Copy Markdown
Contributor Author

@weronika-szalas weronika-szalas Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach allows different underlying components for different variant.

In oakButtonConfig the same values are accepted for each variant but in here we only pass the values relevant to the underlying component.

There is a decision to be made here, we could:

  • unify the underlying components' API so they accept the same set of props, or
  • update oakButtonConfig type to require only values relevant for each variant

Values which are currently needed in InternalShadowRectButton but not in InternalShadowRoundButton:

  • defaultBackground
  • defaultBorderColor
  • hoverBackground
  • hoverBorderColor
  • disabledBackground
  • disabledBorderColor
  • hoverShadow
  • hoverUnderline

Values which are needed in InternalShadowRoundButton but not in InternalShadowRectButton:

  • defaultIconColor
  • defaultIconBackground
  • defaultIconBorderColor
  • hoverIconBackground
  • hoverIconBorderColor
  • disabledIconColor
  • disabledIconBackground
  • disabledIconBorderColor
  • iconBackgroundSize

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropping it here for a reference - this is how the oakButtonConfig would look like if we decided not to make any changes to the underlying components:

export type InternalShadowRectButtonColorProps = {
  defaultTextColor: OakUiRoleToken;
  defaultBackground: OakUiRoleToken;
  defaultBorderColor: OakUiRoleToken;
  hoverTextColor: OakUiRoleToken;
  hoverBackground: OakUiRoleToken;
  hoverBorderColor: OakUiRoleToken;
  disabledTextColor: OakUiRoleToken;
  disabledBackground: OakUiRoleToken;
  disabledBorderColor: OakUiRoleToken;
  hoverShadow: OakDropShadowToken | null;
};

export type InternalShadowRoundButtonColorProps = {
  defaultTextColor: OakUiRoleToken;
  defaultIconColor: OakUiRoleToken;
  defaultIconBackground: OakUiRoleToken;
  defaultIconBorderColor: OakUiRoleToken;
  hoverTextColor: OakUiRoleToken;
  hoverIconColor: OakUiRoleToken;
  hoverIconBackground: OakUiRoleToken;
  hoverIconBorderColor: OakUiRoleToken;
  disabledTextColor:OakUiRoleToken;
  disabledIconColor: OakUiRoleToken;
  disabledIconBackground: OakUiRoleToken;
  disabledIconBorderColor: OakUiRoleToken;
  hoverShadow: OakDropShadowToken | null;
};

/**
 * Specifies props for each variant taking into acccount an underlying component 
 */
type OakButtonVariantConfig = {
  primary: {
    colorSchemes: {
      primary: InternalShadowRectButtonColorProps;
      inverted: InternalShadowRectButtonColorProps;
    },
  },
  secondary: {
    colorSchemes: {
      primary: InternalShadowRectButtonColorProps;
    },
  },
  tertiary: {
    colorSchemes: {
      primary: InternalShadowRoundButtonColorProps;
      inverted: InternalShadowRoundButtonColorProps;
      transparent: InternalShadowRoundButtonColorProps;
    },
  },
};

in OakButton we would then use:

switch (variant) {
    case "primary":
    case "secondary": {
      const rectColorScheme = colorSchemeConfig as InternalShadowRectButtonColorProps;
      return (
        <InternalShadowRectButton
          element={element ?? "button"}
          defaultTextColor={rectColorScheme.defaultTextColor}
          defaultBackground={rectColorScheme.defaultBackground}
          defaultBorderColor={rectColorScheme.defaultBorderColor}
          hoverTextColor={rectColorScheme.hoverTextColor}
          hoverBackground={rectColorScheme.hoverBackground}
          hoverBorderColor={rectColorScheme.hoverBorderColor}
          disabledTextColor={rectColorScheme.disabledTextColor}
          disabledBackground={rectColorScheme.disabledBackground}
          disabledBorderColor={rectColorScheme.disabledBorderColor}
          hoverShadow={rectColorScheme.hoverShadow}
          hoverUnderline
          {...sharedSizeProps}
          {...rest}
        >
          {children}
        </InternalShadowRectButton>
      );
    }
    case "tertiary": {
      const roundColorScheme = colorSchemeConfig as InternalShadowRoundButtonColorProps;
      return (
        <InternalShadowRoundButton
          element={element ?? "button"}
          defaultTextColor={roundColorScheme.defaultTextColor}
          defaultIconColor={roundColorScheme.defaultIconColor}
          defaultIconBackground={roundColorScheme.defaultIconBackground}
          defaultIconBorderColor={roundColorScheme.defaultIconBorderColor}
          hoverTextColor={roundColorScheme.hoverTextColor}
          hoverIconColor={roundColorScheme.hoverIconColor}
          hoverIconBackground={roundColorScheme.hoverIconBackground}
          hoverIconBorderColor={roundColorScheme.hoverIconBorderColor}
          disabledTextColor={roundColorScheme.disabledTextColor}
          disabledIconColor={roundColorScheme.disabledIconColor}
          disabledIconBackground={roundColorScheme.disabledIconBackground}
          disabledIconBorderColor={roundColorScheme.disabledIconBorderColor}
          iconBackgroundSize={sizeConfig.iconBackgroundSize}
          hoverDropShadow={colorSchemeConfig.hoverShadow}
          {...sharedSizeProps}
          {...rest}
        >
          {children}
        </InternalShadowRoundButton>
      );
    }
  }

@weronika-szalas weronika-szalas changed the title Oak button component OakButton component Feb 18, 2026
@weronika-szalas weronika-szalas marked this pull request as ready for review February 18, 2026 12:26
@notion-workspace
Copy link
Copy Markdown

@charsville
Copy link
Copy Markdown
Contributor

Adding this comment for some general feedback and discussion points that I think we need to happen

Thoughts

  1. This PR seems to be doing a lot of things at once right now. Perhaps its better if we break this into 2 phases. Right now it is creating the new Button component, which in itself is a big task. At the same time we are replacing all existing buttons to use the new component. It may be beneficial for us to focus a PR on just the new Button component first, and then we come back to updating usages, and maybe even do that with 1 button type first as a test.
  2. The Button component in this PR is still relying on the internal shadow rect button. Are we still causing an issue here of building lots of components on top of components. Are we better off building this new button from a base HTML button component and this component is then responsible for all styling of a button.
  3. The method for rendering the button variants uses a switch for 2 of the same components but the only differences are the props. I think we should try to always render a single component and if different variants require different props then the implementation of variants should consider how to apply different variant props instead of just styles.
  4. The oakButtonConfig file is very big, and contains a lot of mappings. Is this definitely the best approach? Are there ways to group or reduce this?

Proposed Next Steps

  • Discuss usage of InternalShadowRect and alt child components
  • Discuss options for applying variant props
  • Discuss options for mapping styles for oakConfig
  • Create a new PR that just creates the new Button component with Storybook based on agreement from discussion

Copy link
Copy Markdown
Contributor

@charsville charsville left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment on PR -- I think we should discuss and resolve this before this PR is ready for merge

@messmike messmike removed their request for review March 26, 2026 09:06
@messmike
Copy link
Copy Markdown

messmike commented Apr 2, 2026

Adding these links to the refactored button components in the Design Kit in Figma:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants