<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Reconcept</title>
    <description>The latest articles on DEV Community by Reconcept (@reconcept).</description>
    <link>https://dev.to/reconcept</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F7878%2Fc0ead99d-68f2-4f67-9917-30e41f66c36c.png</url>
      <title>DEV Community: Reconcept</title>
      <link>https://dev.to/reconcept</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/reconcept"/>
    <language>en</language>
    <item>
      <title>Upgrading from Capacitor 2 in 2024 - Lessons Learned</title>
      <dc:creator>Gerhard</dc:creator>
      <pubDate>Wed, 17 Apr 2024 13:31:50 +0000</pubDate>
      <link>https://dev.to/reconcept/upgrading-from-capacitor-2-in-2024-lessons-learned-30ih</link>
      <guid>https://dev.to/reconcept/upgrading-from-capacitor-2-in-2024-lessons-learned-30ih</guid>
      <description>&lt;p&gt;Looking back on the project, there were a few lessons learned and hopefully we can help you with avoiding these mistakes&lt;/p&gt;

&lt;h2&gt;
  
  
  Estimations
&lt;/h2&gt;

&lt;p&gt;When starting the migration project, we estimated that it would take longer than 1 sprint (we do 2 weeks) to fully migrate the application. A big investment, but worth it in the long run.&lt;br&gt;
It turned out to actually be a lot shorter than that; it took 1 FTE about 1 week + some extra for reviews to eventually migrate the project.&lt;br&gt;
The fact that we could upgrade to Capacitor 4 &amp;amp; 5 without having to upgrade all plugins, made progress a lot &lt;br&gt;
faster. &lt;/p&gt;

&lt;p&gt;The biggest trouble we got was from the &lt;code&gt;FileReader&lt;/code&gt;, where we had a ZoneJS instance and a Capacitor instance. This was very tough to find out, but at one point the dots got connected and we found a solution to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Could we have done it better?
&lt;/h2&gt;

&lt;p&gt;Probably, but not by a lot. When we started the project the target was to finish. We might have been better off with some more Proof of Concepts and prototypes to see how the migration would go. That would have given us a better idea and estimation on how to tackle it fully.&lt;/p&gt;

&lt;p&gt;But in the end we are very happy with how the migration has gone and we will be better focused on future releases so we’ll have an easier time &lt;a href="https://ionic.io/blog/Capacitor-6-beta-now-available"&gt;upgrading again&lt;/a&gt;!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Upgrading from Capacitor 2 in 2024 - Part 3: OneSignal</title>
      <dc:creator>Gerhard</dc:creator>
      <pubDate>Wed, 17 Apr 2024 13:31:44 +0000</pubDate>
      <link>https://dev.to/reconcept/upgrading-from-capacitor-2-in-2024-part-3-onesignal-536o</link>
      <guid>https://dev.to/reconcept/upgrading-from-capacitor-2-in-2024-part-3-onesignal-536o</guid>
      <description>&lt;p&gt;Another big plugin we needed to upgrade was the &lt;a href="https://documentation.onesignal.com/docs/ionic-sdk-setup"&gt;OneSignal&lt;/a&gt; notifications plugin. We were still at version 2 for this plugin, with 5 being the latest, so we knew we had some work to do here.&lt;/p&gt;

&lt;p&gt;Unfortunately the &lt;a href="https://documentation.onesignal.com/docs/ionic-sdk-setup"&gt;official documentation&lt;/a&gt; only showed how to initialize and handle a simple notification and we could not find how to migrate the other features we use, like enabling or disabling notifications from the app.&lt;/p&gt;

&lt;p&gt;We tried looking at other solutions, like the &lt;a href="https://Capacitorjs.com/docs/apis/push-notifications"&gt;Capacitor push-notifications&lt;/a&gt;-plugin. It seemed to have everything we needed, but required a full rework of all the code in the app and some backend work too. This was too big of a change to do at that moment, so we had to do more research&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding the treasure
&lt;/h2&gt;

&lt;p&gt;But after some digging in the GitHub repository, we found the &lt;a href="https://github.com/OneSignal/OneSignal-Cordova-SDK/blob/user_model/main/MIGRATION_GUIDE.md"&gt;migration guide&lt;/a&gt;.&lt;br&gt;
Following this guide, we could upgrade the plugin to the latest version, and the only problem we encountered was actually us not fully understanding how OneSignal works with fresh installs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fresh installs equals new subscription
&lt;/h2&gt;

&lt;p&gt;We wanted to test sending a notification to a user, so we found our test device in the subscriptions with OneSignal, &lt;br&gt;
and marked it as a test account. We could then send a test notification, and it showed up on the device.&lt;/p&gt;

&lt;p&gt;So we continued  implementing the enabling and disabling of the notifications from the app. When testing this with our marked test device, we saw no updates happening to the subscription! A lot of frustrations, verbose logging and installations later, we noticed that the UUID of the new install did not match the UUID of the test account!&lt;/p&gt;

&lt;p&gt;So for every new installation, which happens with a rebuild, a new subscription id is used in OneSignal. So we just had to mark the new subscription id as a test account, and the notification arrived.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Upgrading from Capacitor 2 in 2024 - Part 4: Minor plugins</title>
      <dc:creator>Gerhard</dc:creator>
      <pubDate>Wed, 17 Apr 2024 13:31:38 +0000</pubDate>
      <link>https://dev.to/reconcept/upgrading-from-capacitor-2-in-2024-part-4-minor-plugins-52m8</link>
      <guid>https://dev.to/reconcept/upgrading-from-capacitor-2-in-2024-part-4-minor-plugins-52m8</guid>
      <description>&lt;p&gt;There were a few minor plugins that also needed updating:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Camera&lt;/li&gt;
&lt;li&gt;Rating&lt;/li&gt;
&lt;li&gt;Biometrics&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Camera
&lt;/h2&gt;

&lt;p&gt;Capacitor provides a Camera plugin, which we could easily migrate to from the Cordova plugin.&lt;br&gt;
We only had to match the Cordova &lt;code&gt;CameraOptions&lt;/code&gt; to the Capacitor &lt;code&gt;ImageOptions&lt;/code&gt;, and we were good to go. Both plugins returned the same result, a path to the file. This meant no further changes necessary.&lt;/p&gt;

&lt;p&gt;Easy work, hopefully the other plugins coöporate as well.&lt;/p&gt;
&lt;h2&gt;
  
  
  RateApp
&lt;/h2&gt;

&lt;p&gt;As all apps do, we also annoy ask the user for a review whenever possible. But both Android and iOs limit the amount of requests an app can do for a review. For instance, on iOS:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No matter how many times you call the API, the system will only show up to a maximum of 3 prompts to the same user in a 365-day period.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We used &lt;a href="https://github.com/dpa99c/cordova-launch-review"&gt;cordova-launch-review&lt;/a&gt;, which started in 2015 and stopped development in 2020. There was a lot of code recommended by the plugin to check if the user was actually requested for a review, and some management for asking again.&lt;/p&gt;

&lt;p&gt;The new &lt;a href="https://www.npmjs.com/package/Capacitor-rate-app"&gt;RateApp&lt;/a&gt; has a very simple recommendation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { RateApp } from 'Capacitor-rate-app';
RateApp.requestReview();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we removed all the surrounding code for the previous plugin, and now use RateApp as recommended.&lt;/p&gt;

&lt;h2&gt;
  
  
  Biometrics
&lt;/h2&gt;

&lt;p&gt;We offer the feature to the user to use biometric validation, so they can unlock or validate documents using their fingerprint or face.&lt;br&gt;
We store a PIN with this biometric authentication, which we send to the backend when validation is needed.&lt;/p&gt;

&lt;p&gt;The Cordova plugin we used was a forked branch of &lt;a href="https://github.com/sjhoeksma/cordova-plugin-keychain-touch-id.git"&gt;cordova-plugin-keychain-touch-id&lt;/a&gt;. This forked branch had some required updates to work with the newer Android versions.&lt;/p&gt;

&lt;p&gt;The first plugin we tried was &lt;a href="https://github.com/aparajita/Capacitor-biometric-auth"&gt;Capacitor-biometric-auth&lt;/a&gt;, but after implementing the first steps we found out that we couldn’t store the PIN with the authentication, so we had to find something else. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/epicshaggy/Capacitor-native-biometric"&gt;Capacitor-native-biometric&lt;/a&gt; provided the solution we needed. Although they intended to store a username/password with the biometric authentication, we just put the PIN in the password field which worked perfectly.&lt;/p&gt;

&lt;p&gt;The old plugin could tell us if the user had stored a value, without requiring unlocking it. This was not possible in the new plugin, which always requires unlocking before accessing the value. This means we had to do some work, and had to add a feature where we track separately if the user has set the biometrics.&lt;/p&gt;

&lt;p&gt;Unfortunately we can’t migrate the users that use the old plugin to the new plugin. The new plugin stores the PIN in a different way, so with the update it wouldn’t work anymore. So we added a popup notification for the users that uses their biometrics that they need to provide access again. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Upgrading from Capacitor 2 in 2024 - Part 2: Files</title>
      <dc:creator>Gerhard</dc:creator>
      <pubDate>Wed, 17 Apr 2024 09:06:07 +0000</pubDate>
      <link>https://dev.to/reconcept/upgrading-from-capacitor-2-in-2024-part-2-files-1lk5</link>
      <guid>https://dev.to/reconcept/upgrading-from-capacitor-2-in-2024-part-2-files-1lk5</guid>
      <description>&lt;p&gt;Finally, we could start with upgrading the plugins from Cordova to Capacitor.&lt;/p&gt;

&lt;p&gt;The first plugins we chose to upgrade all had to do with handling files. In the application you can attach files to your portfolio, which of course can be chosen from the device.&lt;/p&gt;

&lt;p&gt;We had several plugins to manage this in Cordova, even specific ones for Android and iOS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;@ionic-native/file-chooser (android)&lt;/li&gt;
&lt;li&gt;@ionic-native/file-picker (iOS)&lt;/li&gt;
&lt;li&gt;@ionic-native/image-picker (for iOS &amp;amp; android)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Capacitor, these were all replaced using Capacitors’ &lt;code&gt;Filesystem&lt;/code&gt; plugin. This plugin had all the features we needed, and works basically the same, by returning a path to where the file was located on the devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubles ahead
&lt;/h2&gt;

&lt;p&gt;The trouble began when we wanted to upload the selected file to our back-end, to connect them to the portfolio. We use S3 as storage, and have written code that uses the JavaScript &lt;code&gt;File&lt;/code&gt; interface to upload the file. But the plugins all return a string to the file on the device, not the actual file itself.&lt;/p&gt;

&lt;p&gt;We had a different Cordova plugin to handle this &lt;code&gt;@ionic-native/file&lt;/code&gt;, that added a function called &lt;code&gt;resolveLocalFileSystemURL&lt;/code&gt;. This returns a JavaScript &lt;code&gt;File&lt;/code&gt; from the given path, which we used in our code to upload.&lt;/p&gt;

&lt;p&gt;Here again, Capacitors’ &lt;code&gt;Filesystem&lt;/code&gt; came to the rescue. The &lt;code&gt;readFile&lt;/code&gt; function returns a base64 encoded string from the file contents. Then using some ‘&lt;a href="https://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript"&gt;inspiration&lt;/a&gt;’ from stack overflow, we created a &lt;code&gt;Blob&lt;/code&gt; from which we can create the &lt;code&gt;File&lt;/code&gt; instance we need for our existing code.&lt;/p&gt;

&lt;p&gt;This all made sense in theory, but when executing the code we found that the contents of the file were always empty. &lt;br&gt;
We went deep into the plugin’s code to see what was going on, and we saw that the &lt;code&gt;readFile&lt;/code&gt; function &lt;em&gt;uses the &lt;code&gt;FileReader&lt;/code&gt; from the browser the app is running in&lt;/em&gt; But because the Capacitor plugins run outside of the Angular zone, we’d get a different instance for this &lt;code&gt;FileReader&lt;/code&gt; than the one we get from ZoneJS to upload the file to the S3 storage!.&lt;/p&gt;

&lt;h1&gt;
  
  
  Patching FileReader
&lt;/h1&gt;

&lt;p&gt;We found &lt;a href="https://github.com/ionic-team/Capacitor/issues/1564#issuecomment-1006942075"&gt;some help on the internet&lt;/a&gt;, and now we patch the &lt;code&gt;FileReader&lt;/code&gt; constructor to always use the instance used by ZoneJS (if present). Lovely stuff.&lt;br&gt;
The last plugins concerning files were the &lt;code&gt;FileOpener&lt;/code&gt; and &lt;code&gt;PhotoViewer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;FileOpener&lt;/code&gt; requests the OS for an app to open the file, and we found that the plugin from the Capacitor community &lt;code&gt;@Capacitor-community/file-opener&lt;/code&gt; was a near drop-in replacement for the Cordova version. &lt;br&gt;
For the photo viewer, we also chose a community plugin: &lt;code&gt;@Capacitor-community/photoviewer&lt;/code&gt;. This one actually had quite a few installation steps, because the plugin is written in Kotlin, but the steps were clear to follow and the plugin worked immediately.&lt;/p&gt;

&lt;p&gt;The upgrading of the file handling in the app had some up’s and downs. Some plugins were easily replaced, but the whole &lt;code&gt;FileReader&lt;/code&gt; issue caused a lot of headaches. Some luck was needed to realise the problem with the multiple instances, but the fix/hack works like a dream/nightmare.&lt;/p&gt;

&lt;p&gt;If all plugins cause problems like this, we might have a bumpier road ahead of us then we’d like.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Upgrading from Capacitor 2 in 2024 - Part 1</title>
      <dc:creator>Gerhard</dc:creator>
      <pubDate>Wed, 17 Apr 2024 09:05:50 +0000</pubDate>
      <link>https://dev.to/reconcept/upgrading-from-capacitor-2-in-2024-part-1-2gig</link>
      <guid>https://dev.to/reconcept/upgrading-from-capacitor-2-in-2024-part-1-2gig</guid>
      <description>&lt;p&gt;The first step was trying to estimate the amount of work that needed to be done. This resulted in the following plan:&lt;/p&gt;

&lt;h3&gt;
  
  
  #1
&lt;/h3&gt;

&lt;p&gt;Lay the ground work&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;update Capacitor to v4, fix plugins that are not compatible&lt;/li&gt;
&lt;li&gt;update Capacitor to v5 (latest), fix plugins that are not compatible.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  #2
&lt;/h3&gt;

&lt;p&gt;Then update rest of plugins:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FilePicker&lt;/li&gt;
&lt;li&gt;FileOpener&lt;/li&gt;
&lt;li&gt;Photoviewer&lt;/li&gt;
&lt;li&gt;Camera&lt;/li&gt;
&lt;li&gt;App Review&lt;/li&gt;
&lt;li&gt;Biometrics&lt;/li&gt;
&lt;li&gt;Notifications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We weren’t sure if we could even build the app while upgrading to test the individual parts, so even the first step could become a huge hurdle before we even got to see the results. For this reason we estimated this could take over 1 sprint to do, but if we don’t start now it won’t become any easier either.&lt;/p&gt;

&lt;p&gt;So we just started and would see what happens. We have the daily standup for check-ins, to see how it’s going and if we need to change our approach or maybe get some extra help.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migration to Capacitor 4.
&lt;/h2&gt;

&lt;p&gt;The Capacitor CLI provides a migration tool that can be run to easily update the Android &amp;amp; iOS specific files, so we don’t have to manually go through the platform specific configuration files. We followed the instructions in the &lt;a href="https://Capacitorjs.com/docs/updating/4-0"&gt;Updating to 4.0&lt;/a&gt; guide, the files were updated and the only thing left to do was try to start up the app and see what needed to be fixed.&lt;/p&gt;

&lt;p&gt;The next step was upgrading the local Java version from 8 to 11, which was required for Android. &lt;br&gt;
Then we needed to migrate from &lt;code&gt;@Capacitor/storage&lt;/code&gt; to the new &lt;code&gt;@Capacitor/preferences&lt;/code&gt; and thought, this is where the ‘fun’ begins.&lt;/p&gt;

&lt;p&gt;But luckily the API of the new &lt;code&gt;Preferences&lt;/code&gt; and &lt;code&gt;Storage&lt;/code&gt; were basically the same, and we were happily surprised that the app immediately started and we were able to use the outdated Cordova plugins with the new version&lt;br&gt;
This means we can easily migrate each plugin and test it without having to change the entire application.&lt;/p&gt;

&lt;p&gt;Hopefully the migration to the next version is just as easy…&lt;/p&gt;
&lt;h2&gt;
  
  
  Migration to Capacitor 5: A New Hope
&lt;/h2&gt;

&lt;p&gt;For the migration to the next major version, we followed the next migration guide &lt;a href="https://Capacitorjs.com/docs/updating/5-0"&gt;Updating to 5.0&lt;/a&gt;. However, we also noticed a page &lt;a href="https://Capacitorjs.com/docs/updating/plugins/5-0"&gt;Updating plugins to 5.0&lt;/a&gt;. This page described the things the plugin developers needed to do to upgrade to the latest Capacitor version.&lt;/p&gt;

&lt;p&gt;Surely this would mean our smooth sailing would be over?&lt;/p&gt;

&lt;p&gt;We started the migration using the &lt;code&gt;migrate&lt;/code&gt; command from the CLI, updated Java to version 17 and started the application.&lt;/p&gt;

&lt;p&gt;Again, the build succeeded and the application started. At first a sigh of relief, but when we tried to login to the application we were met with an ‘invalid credentials’ error.&lt;br&gt;
After some digging, we found that the &lt;code&gt;ionic-native/http&lt;/code&gt; plugin we use for logging in, could not handle the secure cookies. This was due to a change in the android manifest file by the migration:&lt;br&gt;
from:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;data android:scheme="nl.reconcept.portfolio.universal"/&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;to&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;data android:host="reconcept.app" android:scheme="https"/&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;To fix this, we used the Capacitor provided plugin &lt;code&gt;CapacitorHttp&lt;/code&gt;, which has built-in cookie handling. Luckily, changing the code to use the new plugin did not have any big complications and when it was done we were able to login again.&lt;br&gt;
Our expected struggles did not happen, which allowed us to update the features one by one. This was very good news and gave us hope that the rest of the project would be a lot less work.&lt;/p&gt;

&lt;p&gt;But, when we started work on upgrading the Cordova plugins to their Capacitor counterparts, we were met with some tricky differences.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Upgrading from Capacitor v2 in 2024</title>
      <dc:creator>Gerhard</dc:creator>
      <pubDate>Wed, 17 Apr 2024 09:05:34 +0000</pubDate>
      <link>https://dev.to/reconcept/upgrading-from-capacitor-v2-in-2024-5eka</link>
      <guid>https://dev.to/reconcept/upgrading-from-capacitor-v2-in-2024-5eka</guid>
      <description>&lt;p&gt;This is the story of how we moved our Ionic app from Cordova + Capacitor 2/3 to the latest Capacitor 5 + Capacitor plugins.&lt;/p&gt;

&lt;h2&gt;
  
  
  First some background
&lt;/h2&gt;

&lt;p&gt;We have a simplified version of our web application available on mobile through the App Stores, which allows our users to quickly add to their portfolio.&lt;/p&gt;

&lt;p&gt;The app is built in Ionic, using a mix of Cordova and Capacitor plugins to communicate with the native systems. To name a few systems that we use:&lt;br&gt;
Filesystem to handle file interactions like selecting, uploading and viewing. &lt;br&gt;
Camera plugin  is used to set a profile picture&lt;br&gt;
Biometric features of the phone to quickly unlock the app and validate documents.&lt;/p&gt;

&lt;p&gt;Furthermore we send notifications using OneSignal, and need to listen for these in the background while the app is not running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not upgrade sooner?
&lt;/h2&gt;

&lt;p&gt;The Cordova plugins have always worked, and we never really required more features from the phones so the plugins were not kept up to date. It was on our radar, but it never had enough priority to do something about. If it ain’t broken, don’t fix it, right?&lt;/p&gt;

&lt;p&gt;Then the unthinkable happened, we wanted to build a new feature using something native: a badge on the app icon showing actionable items for the user. We quickly found a plugin that could provide this feature, but it was built for the latest Capacitor version, while we were almost 3 major versions behind.&lt;/p&gt;

&lt;p&gt;This gave us the incentive to update the used Capacitor version to the latest and replace the plugins from Cordova with their new Capacitor counterparts.&lt;/p&gt;

&lt;p&gt;In this multipart series, we’ll go into our experiences while upgrading the app from ancient history to modern times.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parts
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;This intro&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/reconcept/upgrading-from-capacitor-2-in-2024-part-1-2gig"&gt;Start of the migration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/reconcept/upgrading-from-capacitor-2-in-2024-part-2-files-1lk5"&gt;Files&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/reconcept/upgrading-from-capacitor-2-in-2024-part-3-onesignal-536o"&gt;OneSignal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/reconcept/upgrading-from-capacitor-2-in-2024-part-4-minor-plugins-52m8"&gt;Camera, Reviews and Biometrics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/reconcept/upgrading-from-capacitor-2-in-2024-lessons-learned-30ih"&gt;Lessons Learned&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>[tiu] Container Queries</title>
      <dc:creator>Gerhard</dc:creator>
      <pubDate>Tue, 05 Dec 2023 06:26:56 +0000</pubDate>
      <link>https://dev.to/reconcept/tiu-container-queries-2g5a</link>
      <guid>https://dev.to/reconcept/tiu-container-queries-2g5a</guid>
      <description>&lt;p&gt;In this edition of &lt;em&gt;Today I Used&lt;/em&gt;: &lt;strong&gt;Container Queries&lt;/strong&gt;. How can this feature help overcome the limitations of media queries?&lt;/p&gt;

&lt;h2&gt;
  
  
  The situation
&lt;/h2&gt;

&lt;p&gt;A while back we got feedback from a user that they were unable to access an important feature in our application.&lt;br&gt;
We found that on smaller screens, a part of the application would fall outside of the available screen area. Important controls were not available anymore for the user, unless they zoomed out a lot.&lt;/p&gt;

&lt;p&gt;A quick solution would be to add the css-rule &lt;code&gt;overflow-x: scroll&lt;/code&gt; and be done with it, but there is probably a nicer way to do this.&lt;/p&gt;
&lt;h2&gt;
  
  
  The solution?
&lt;/h2&gt;

&lt;p&gt;We started with using &lt;code&gt;@media&lt;/code&gt; queries to show shorter texts and move information behind tooltips which can be activated using a hover. This made enough room so the application is fully visible on smaller screens.&lt;/p&gt;

&lt;p&gt;This seemed to solve the issue, except for a few problems: we have a toggleable side navigation, which reduces the available space by about 250px. When expanded, it would mess with the &lt;code&gt;@media&lt;/code&gt; queries' breakpoints and show a scrollbar. &lt;/p&gt;

&lt;p&gt;Also, when the user zooms in, the window size stays the same but the content grows in size. The &lt;code&gt;@media&lt;/code&gt; queries won't trigger and the scroll bar is shown. &lt;/p&gt;

&lt;p&gt;Lastly we had to choose different breakpoints then our global ones, since the breakpoints were dependant on the content in the screen. These breakpoints felt a bit random, since it was hard to pick 'nice' values.&lt;/p&gt;
&lt;h2&gt;
  
  
  Container queries to the rescue
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;@container&lt;/code&gt; queries work the same as &lt;code&gt;@media&lt;/code&gt; queries but instead of using the entire window as a measurement, you can target an HTML element to listen to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.table-container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;container-type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inline-size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;use&lt;/span&gt; &lt;span class="err"&gt;the&lt;/span&gt; &lt;span class="err"&gt;inner&lt;/span&gt; &lt;span class="err"&gt;dimensions&lt;/span&gt;
  &lt;span class="py"&gt;container-name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;role-table&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;give&lt;/span&gt; &lt;span class="err"&gt;it&lt;/span&gt; &lt;span class="err"&gt;a&lt;/span&gt; &lt;span class="err"&gt;name,&lt;/span&gt; &lt;span class="err"&gt;to&lt;/span&gt; &lt;span class="err"&gt;reference&lt;/span&gt; 
  &lt;span class="nl"&gt;overflow-x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;            &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;scroll,&lt;/span&gt; &lt;span class="err"&gt;if&lt;/span&gt; &lt;span class="err"&gt;needed&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can target this container using &lt;code&gt;@container &amp;lt;&amp;lt;container-name&amp;gt;&lt;/code&gt;. The following code toggles the short and long header names.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@container&lt;/span&gt; &lt;span class="n"&gt;role-table&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;750px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.table&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;.short-header&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;table-cell&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nc"&gt;.long-header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@container&lt;/span&gt; &lt;span class="n"&gt;role-table&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;750px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.table&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;.short-header&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nc"&gt;.long-header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;table-cell&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the breakpoints activate correctly when the sidebar is toggled, since this reduces the available width of the container. Also we can be specific about the available size of the specified container, and not have seemingly random &lt;code&gt;@media&lt;/code&gt; query breakpoints in the codebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extra cool feature
&lt;/h3&gt;

&lt;p&gt;Another cool feature of &lt;code&gt;@container&lt;/code&gt;-queries is that they provide &lt;code&gt;container query length units&lt;/code&gt;. These are special units that specify a length relative to the dimensions of a query container.&lt;/p&gt;

&lt;p&gt;The container query length units are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cqw&lt;/code&gt;: 1% of a query container's width&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cqh&lt;/code&gt;: 1% of a query container's height&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cqi&lt;/code&gt;: 1% of a query container's inline size&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cqb&lt;/code&gt;: 1% of a query container's block size&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cqmin&lt;/code&gt;: The smaller value of either cqi or cqb&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cqmax&lt;/code&gt;: The larger value of either cqi or cqb&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means you can smoothly change the size of for instance the font, based on the container size.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@container role-table (min-width: 700px) {
  .title {
    font-size: max(1.5em, 1.23em + 2cqi);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  More info
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_container_queries"&gt;MDN: CSS Container Queries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://caniuse.com/?search=container%20query"&gt;Can I Use: Container Query&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Reconcept Dev Blogs</title>
      <dc:creator>Gerhard</dc:creator>
      <pubDate>Mon, 20 Nov 2023 13:28:26 +0000</pubDate>
      <link>https://dev.to/reconcept/reconcept-dev-blogs-13b1</link>
      <guid>https://dev.to/reconcept/reconcept-dev-blogs-13b1</guid>
      <description>&lt;p&gt;Welcome to the Reconcept Dev Blogs.&lt;/p&gt;

&lt;p&gt;This is the start of a series where we will explain how the development of our Portfolio platform unfolds.&lt;/p&gt;

&lt;p&gt;We will discuss smaller solutions, as well as larger projects and how we approached them. Additionally, we would like to share interesting things we have come across as developers.&lt;/p&gt;

&lt;p&gt;We are also administrators of the Frontend Developers Groningen meetup. We strive to organize a meetup once per quarter to share knowledge and connect with fellow developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  About Reconcept
&lt;/h2&gt;

&lt;p&gt;At Reconcept, we create a Portfolio platform focused on medical education. The Portfolio provides the ability to capture practical feedback and link it to various topics such as skills or themes.&lt;/p&gt;

&lt;p&gt;We have split the platform into different applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Portfolio, the main application&lt;/li&gt;
&lt;li&gt;Login, a separate login application for OAuth&lt;/li&gt;
&lt;li&gt;Support, our backoffice&lt;/li&gt;
&lt;li&gt;Portfolio App, a mobile version available in the App Stores&lt;/li&gt;
&lt;li&gt;Quality Dashboard, an additional application for ensuring education quality through the PDCA cycle.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tech Stack
&lt;/h3&gt;

&lt;p&gt;The frontend(s) are built with Angular, with Ionic for the mobile app.&lt;br&gt;
The backend is built with Ruby on Rails.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Reconcept Dev Blogs (Dutch)</title>
      <dc:creator>Gerhard</dc:creator>
      <pubDate>Mon, 20 Nov 2023 13:28:16 +0000</pubDate>
      <link>https://dev.to/reconcept/reconcept-dev-blogs-dutch-2n4l</link>
      <guid>https://dev.to/reconcept/reconcept-dev-blogs-dutch-2n4l</guid>
      <description>&lt;p&gt;Welkom bij de Reconcept Dev Blogs.&lt;/p&gt;

&lt;p&gt;Dit is de start van een serie waarbij we uit de doeken doen hoe het ontwikkelen van ons Portfolio platform eraan toe gaat.&lt;/p&gt;

&lt;p&gt;We gaan het hebben over kleinere oplossingen, maar ook over grotere projecten en hoe we die hebben aangepakt. Daarnaast willen we graag dingen delen die we als developers interessant vonden die we zijn tegengekomen.&lt;/p&gt;

&lt;p&gt;Ook zijn we beheerders van de Frontend Developers Groningen meetup. We proberen 1x per kwartaal een meetup te organiseren om kennis te delen en te connecten met onze mede developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Over Reconcept
&lt;/h2&gt;

&lt;p&gt;Bij Reconcept maken we een Portfolio platform gericht op de medische opleidingen. Het Portfolio biedt de mogelijkheid om praktijkgerichte feedback vast te leggen, en deze te koppelen aan verschillende onderwerpen zoals vaardigheden of thema's. &lt;/p&gt;

&lt;p&gt;We hebben het platform opgesplitst in verschillende applicaties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Portfolio, de hoofdapplicatie&lt;/li&gt;
&lt;li&gt;Login, aparte login applicatie voor OAuth&lt;/li&gt;
&lt;li&gt;Support, onze backoffice&lt;/li&gt;
&lt;li&gt;Portfolio App, mobiele versie beschikbaar in de App Stores&lt;/li&gt;
&lt;li&gt;Kwaliteitsdashboard, een extra applicatie waarmee de opleiding via de PDCA cyclus en kwaliteit kan waarborgen.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tech Stack
&lt;/h3&gt;

&lt;p&gt;De frontend(s) zijn gebouwd in Angular, met Ionic voor de mobiele app.&lt;br&gt;
De backend is gebouwd in Ruby on Rails.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
