{"id":1424,"date":"2018-02-18T21:27:57","date_gmt":"2018-02-18T21:27:57","guid":{"rendered":"https:\/\/officedevblogs.wpengine.com\/?p=1424"},"modified":"2018-02-18T21:27:57","modified_gmt":"2018-02-18T21:27:57","slug":"microsoft-teams-app-studios-control-library","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/microsoft-teams-app-studios-control-library\/","title":{"rendered":"Microsoft Teams App Studio&#8217;s Control Library"},"content":{"rendered":"<p>If you\u2019ve tried out our new\u00a0<a href=\"https:\/\/techcommunity.microsoft.com\/t5\/Microsoft-Teams-Blog\/Microsoft-Teams-App-Studio-Preview\/ba-p\/150103\/jump-to\/first-unread-message\" target=\"_blank\" rel=\"noopener noreferrer\">Microsoft Teams App Studio<\/a>\u00a0you\u2019ve probably noticed the \u201cControl library\u201d tab. We developed this library based on feedback from our developer community to simplify the design and development process. Each time we created a new tab we found ourselves copying the same CSS code repeatedly \u2014 as you can imagine there were several issues:<\/p>\n<ul>\n<li>Every time the Microsoft Teams designers made a visual change, we needed to update the CSS for every tab<\/li>\n<li>Teams client supports three different themes, light (the default), dark, and high-contrast; all of which need to be updated<\/li>\n<li>The keyboard navigation behavior across controls becomes inconsistent in different tabs if they are implemented differently<\/li>\n<\/ul>\n<p>To resolve these issues, we built a library for common UI elements used in Teams. Using this library will enable your tab to stay consistent with the Teams look and feel.<\/p>\n<p>While the full Teams control library uses the\u00a0<a href=\"https:\/\/reactjs.org\/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">React UI framework<\/a>, it\u2019s built so that it\u2019s not tied to a specific UI framework. In fact, we have four different npm packages:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/msteams-ui-styles-core\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">msteams-ui-styles-core<\/a>\u00a0&#8211; The core CSS styles of UI components. It\u2019s independent of any UI framework.<\/li>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/msteams-ui-icons-core\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">msteams-ui-icons-core<\/a>\u00a0&#8211; The core set of Teams icons.<\/li>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/msteams-ui-components-react\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">msteams-ui-components-react<\/a>\u00a0&#8211; The React binding library. It depends on msteams-ui-styles-core.<\/li>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/msteams-ui-icons-react\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">msteams-ui-icons-react<\/a>\u00a0&#8211; The React binding library for the set of Teams icons. It depends on msteams-ui-icons-react.<\/li>\n<\/ul>\n<p>They are all open source; you can use msteams-ui-styles-core and msteams-ui-icons-core without React. Assuming you already use React or are willing to try, here\u2019s what to do:<\/p>\n<ol start=\"1\">\n<li><a href=\"https:\/\/github.com\/facebook\/create-react-app\" target=\"_blank\" rel=\"noopener noreferrer\">Create a react app<\/a>. Skip if you have an existing one:<\/li>\n<\/ol>\n<pre>create-react-app hello-teams &amp;&amp; cd hello-teams<\/pre>\n<ol start=\"2\">\n<li>Install control library and its peer dependency \u2018typestyle\u2019<\/li>\n<\/ol>\n<pre>npm install --save typestyle &amp;&amp; npm install --save msteams-ui-components-react<\/pre>\n<p>Optionally, install msteams-ui-icons-react if you want to use Teams icons.<\/p>\n<pre>npm install --save msteams-ui-icons-react<\/pre>\n<ol start=\"3\">\n<li>Edit `src\/App.js` file, replace its content with following code:<\/li>\n<\/ol>\n<pre>import React, { Component } from \u2018react\u2019;\nimport { TeamsComponentContext, ThemeStyle, PrimaryButton } from \u2018msteams-ui-components-react\u2019\n\nclass App extends Component {\n   render() {\n      \/\/ Sets up the top-level context for the library. It accepts global\n      \/\/ configurations, e.g. font size and theme. fontSize is your page\u2019s\n      \/\/ default font size. We made it a parameter so that you could use this\n      \/\/ library with CSS frameworks such as Bootstrap. Some CSS frameworks\n      \/\/ set the default font size for the page; retrieve it and use it \n      \/\/ instead of {16} in the block. \n      \/\/ This library uses the power of CSS to most of the work for you.\n      \/\/ Instead of passing themes as a parameter to every UI component, \n      \/\/ we set it on a parent HTML element. All HTML elements nested within \n      \/\/ that parent will inherit these properties. \n      return (\n\t&lt;TeamsComponentContext\n  \t    fontSize={16}\n\t    theme={ThemeStyle.Light}\n        \/&gt;\n      );\n   }\n}\n\nexport default App;\n<\/pre>\n<ol start=\"4\">\n<li>Run<\/li>\n<\/ol>\n<pre>npm run start<\/pre>\n<ol start=\"5\">\n<li>When you navigate to\u00a0<a href=\"http:\/\/localhost:3000\/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">http:\/\/localhost:3000<\/a>, you should see your button.<\/li>\n<\/ol>\n<h2 id=\"toc-hId--734918012\">Dynamically Handling Theme Change<\/h2>\n<p>You need to handle themes in two scenarios: one when the tab is initially loaded, and the other when a user changes the theme after the tab is already loaded. The theme is included in a tab\u2019s\u00a0<a href=\"https:\/\/docs.microsoft.com\/en-us\/javascript\/api\/msteams-client\/microsoftteams.context\" target=\"_blank\" rel=\"noopener noreferrer\">Context<\/a>, which\u00a0<a href=\"https:\/\/docs.microsoft.com\/en-us\/microsoftteams\/platform\/concepts\/tabs\/tabs-context#accessing-context\" target=\"_blank\" rel=\"noopener noreferrer\">can be retrieved before the tab is loaded via URL placeholder values, or at any time by using micros&#8230;<\/a>from the\u00a0<a href=\"https:\/\/docs.microsoft.com\/en-us\/javascript\/api\/overview\/msteams-client\" target=\"_blank\" rel=\"noopener noreferrer\">Microsoft Teams JavaScript client SDK<\/a>. How the current theme is retrieved and how to respond to theme changes is discussed here:\u00a0<a href=\"https:\/\/docs.microsoft.com\/en-us\/microsoftteams\/platform\/concepts\/tabs\/tabs-context\" target=\"_blank\" rel=\"noopener noreferrer\">Get context for your Microsoft Teams tab<\/a>.<\/p>\n<p>The sample code below shows how this is done.<\/p>\n<pre>componentWillMount() {\n\t\/\/ If you are deploying your site as a MS Teams static or configurable tab,\n\t\/\/ you should add \u201c?theme={theme}\u201d to your tabs URL in the manifest.\n\t\/\/ That way you will get the current theme before it\u2019s loaded; getContext()\n\t\/\/ is called only after the tab is loaded, which will cause the tab to flash\n\t\/\/ if the current theme is different than the default.\n\tthis.updateTheme(this.getQueryVariable('theme'));\n\tthis.setState({\n\t   fontSize: this.pageFontSize(),\n\t});\n\n\t\/\/ If you are not using the MS Teams Javascript SDK, you can remove this entire\n\t\/\/ if block, but if you want theme changes in the MS Teams client to propagate\n\t\/\/ to the tab, leave it here.\n\tif (this.inTeams()) {\n\t   microsoftTeams.initialize();\n\t   microsoftTeams.registerOnThemeChangeHandler(this.updateTheme);\n\t}\n   }\n<\/pre>\n<h2 id=\"toc-hId-1007892323\">Connect Your Own Component to the TeamsComponentContext<\/h2>\n<p>Sometimes you want to write your own CSS code and still use some colors defined by Teams. Sometimes you want to write your own CSS code but still respond to theme change. We offer a way to hook your component with TeamsComponentContext.<\/p>\n<p>Once again, edit your \u2018src\/App.js\u2019 file and replace its content with following code:<\/p>\n<pre>import React, { Component } from \u2018react\u2019;\nimport { TeamsComponentContext, ThemeStyle, ConnectedComponent } from \u2018msteams-ui-components-react\u2019\n\nclass App extends Component {\n   render() {\n      return (\n\t&lt;TeamsComponentContext\n\t  fontSize={16}\n\t  theme={ThemeStyle.HighContrast}&gt;\n\t  &lt;MyComponent \/&gt;\n\t&lt;\/TeamsComponentContext&gt;\n       );\n     }\n }\n \nclass MyComponent extends Component {\n   render() {\n      return (\n\t&lt;ConnectedComponent render={(props) =&gt; {\n\t  const context = props.context;\n\n\t  switch (context.style) {\n\t    case ThemeStyle.Dark:\n\t      return &lt;div style={{ color: context.colors.dark.brand00 }}&gt;Dark theme!&lt;\/div&gt;;\n\t    case ThemeStyle.HighContrast:\n\t      return &lt;div style={{ color: context.colors.highContrast.black }}&gt;High Contrast theme!&lt;\/div&gt;;\n\t    case ThemeStyle.Light:\n\t      return &lt;div style={{ color: context.colors.light.brand00 }}&gt;Light theme!&lt;\/div&gt;;\n\t  }\n\t}} \/&gt;\n      );\n   }\n}\n\nexport default App;<\/pre>\n<p>In the above code, we define a new component called\u00a0<strong>MyComponent<\/strong>. We then use a special component offered by the control library called\u00a0<strong>ConnectedComponent<\/strong>.\u00a0<strong>ConnectedComponent<\/strong>\u00a0has a property called\u00a0<em>render<\/em>\u00a0which takes a function as parameter. At render time, this function will be called with the appropriate context for your tab. The context includes the theme that the page is being rendered in as well as the global color object that you can use to apply Teams colors to your tab. As you can see in the\u00a0<em>switch<\/em>\u00a0statement above, we choose the theme appropriate div to render.<\/p>\n<p>To change themes, we need to pass the root-level TeamsComponentContext a different theme. When a theme changes, all the child elements wrapped in ConnectedComponent will be re-rendered. See previous section \u201cDynamically Handle Theme Change.\u201d<\/p>\n<h3 id=\"toc-hId--1740778143\">Alternative Way to Connect Your Component to TeamsComponentContext:<\/h3>\n<p>If you\u2019re familiar with\u00a0<a href=\"https:\/\/redux.js.org\/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Redux<\/a>, you may prefer the following way of connecting to TeamsComponentContext:<\/p>\n<pre>import React, { Component } from \u2018react\u2019;\nimport { TeamsComponentContext, ThemeStyle, connectTeamsComponent } from \u2018msteams-ui-components-react\u2019\n\nclass App extends Component {\n   render() {\n     return (\n\t&lt;TeamsComponentContext\n\tfontSize={16}\n\ttheme={ThemeStyle.HighContrast}&gt;\n\t&lt;MyComponent \/&gt;\n\t&lt;\/TeamsComponentContext&gt;\n      );\n   }\n}\n\nclass MyComponentInner extends Component {\n   render() {\n      const context = this.props.context;\n      switch (context.style) {\n\tcase ThemeStyle.Dark:\n\t   return &lt;div style={{ color: context.colors.dark.brand00 }}&gt;Dark theme!&lt;\/div&gt;;\n\tcase ThemeStyle.HighContrast:\n\t   return &lt;div style={{ color: context.colors.highContrast.black }}&gt;High Contrast theme!&lt;\/div&gt;;\n\tcase ThemeStyle.Light:\n\t   return &lt;div style={{ color: context.colors.light.brand00 }}&gt;Light theme!&lt;\/div&gt;;\n      }\n   }\n }\n\nconst MyComponent = connectTeamsComponent(MyComponentInner);\n\nexport default App;<\/pre>\n<p>In this method, instead of using\u00a0<strong>ConnectedComponent<\/strong>, we use the\u00a0<em>connectTeamsComponent<\/em>\u00a0function. The\u00a0<em>connectTeamsComponent<\/em>\u00a0function takes your current component and returns a new component with the\u00a0<a href=\"https:\/\/docs.microsoft.com\/en-us\/javascript\/api\/msteams-client\/microsoftteams.context\" target=\"_blank\" rel=\"noopener noreferrer\"><em>context<\/em><\/a>\u00a0object injected.<\/p>\n<h2 id=\"toc-hId-198545697\">Next Steps<\/h2>\n<p>Head to\u00a0<a href=\"https:\/\/techcommunity.microsoft.com\/t5\/Microsoft-Teams-Blog\/Microsoft-Teams-App-Studio-Preview\/ba-p\/150103\/jump-to\/first-unread-message\" target=\"_blank\" rel=\"noopener noreferrer\">Teams App Studio<\/a>\u00a0and check out all the elements we offer and sample code of how to use them. Don\u2019t forget to explore them in different themes!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you\u2019ve tried out our new Microsoft Teams App Studio you\u2019ve probably noticed the \u201cControl library\u201d tab. We developed this library based on feedback from our developer community to simplify the design and development process. Each time we created a new tab we found ourselves copying the same CSS code repeatedly \u2014 as you can imagine there were several issues. To resolve these issues, we built a library for common UI elements used in Teams. Using this library will enable your tab to stay consistent with the Teams look and feel.<\/p>\n","protected":false},"author":69074,"featured_media":25159,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[128],"tags":[82,21],"class_list":["post-1424","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-microsoft-teams","tag-app-studio","tag-connectors"],"acf":[],"blog_post_summary":"<p>If you\u2019ve tried out our new Microsoft Teams App Studio you\u2019ve probably noticed the \u201cControl library\u201d tab. We developed this library based on feedback from our developer community to simplify the design and development process. Each time we created a new tab we found ourselves copying the same CSS code repeatedly \u2014 as you can imagine there were several issues. To resolve these issues, we built a library for common UI elements used in Teams. Using this library will enable your tab to stay consistent with the Teams look and feel.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts\/1424","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/users\/69074"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/comments?post=1424"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts\/1424\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/media\/25159"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/media?parent=1424"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/categories?post=1424"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/tags?post=1424"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}